summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yml35
-rw-r--r--.github/workflows/ci_bench.yml115
-rw-r--r--.github/workflows/ci_gcc14.yml76
-rw-r--r--changelog.md93
-rw-r--r--changelogs/changelog_2_2_0.md238
-rw-r--r--changelogs/changelog_X_XX_X.md2
-rw-r--r--compiler/ast.nim68
-rw-r--r--compiler/astyaml.nim2
-rw-r--r--compiler/backendpragmas.nim25
-rw-r--r--compiler/cbuilder.nim174
-rw-r--r--compiler/ccgcalls.nim120
-rw-r--r--compiler/ccgexprs.nim257
-rw-r--r--compiler/ccgreset.nim16
-rw-r--r--compiler/ccgstmts.nim79
-rw-r--r--compiler/ccgthreadvars.nim4
-rw-r--r--compiler/ccgtrav.nim18
-rw-r--r--compiler/ccgtypes.nim265
-rw-r--r--compiler/ccgutils.nim5
-rw-r--r--compiler/cgen.nim267
-rw-r--r--compiler/cgendata.nim2
-rw-r--r--compiler/cgmeth.nim2
-rw-r--r--compiler/closureiters.nim201
-rw-r--r--compiler/commands.nim11
-rw-r--r--compiler/condsyms.nim3
-rw-r--r--compiler/dfa.nim16
-rw-r--r--compiler/docgen.nim8
-rw-r--r--compiler/evaltempl.nim14
-rw-r--r--compiler/expanddefaults.nim2
-rw-r--r--compiler/extccomp.nim31
-rw-r--r--compiler/ic/ic.nim85
-rw-r--r--compiler/ic/iclineinfos.nim (renamed from compiler/nir/nirlineinfos.nim)2
-rw-r--r--compiler/ic/integrity.nim10
-rw-r--r--compiler/ic/navigator.nim4
-rw-r--r--compiler/ic/packed_ast.nim4
-rw-r--r--compiler/ic/rodfiles.nim27
-rw-r--r--compiler/importer.nim3
-rw-r--r--compiler/injectdestructors.nim40
-rw-r--r--compiler/installer.ini4
-rw-r--r--compiler/jsgen.nim251
-rw-r--r--compiler/lambdalifting.nim61
-rw-r--r--compiler/liftdestructors.nim36
-rw-r--r--compiler/lineinfos.nim7
-rw-r--r--compiler/llstream.nim1
-rw-r--r--compiler/lookups.nim62
-rw-r--r--compiler/main.nim39
-rw-r--r--compiler/modulegraphs.nim73
-rw-r--r--compiler/msgs.nim38
-rw-r--r--compiler/ndi.nim2
-rw-r--r--compiler/nim.nim6
-rw-r--r--compiler/nir/ast2ir.nim2638
-rw-r--r--compiler/nir/cir.nim983
-rw-r--r--compiler/nir/nir.nim105
-rw-r--r--compiler/nir/nirc.nim52
-rw-r--r--compiler/nir/nirfiles.nim83
-rw-r--r--compiler/nir/nirinsts.nim582
-rw-r--r--compiler/nir/nirslots.nim104
-rw-r--r--compiler/nir/nirtypes.nim475
-rw-r--r--compiler/nir/nirvm.nim1175
-rw-r--r--compiler/nir/stringcases.nim200
-rw-r--r--compiler/nir/types2ir.nim525
-rw-r--r--compiler/nodekinds.nim1
-rw-r--r--compiler/options.nim35
-rw-r--r--compiler/parampatterns.nim13
-rw-r--r--compiler/parser.nim2
-rw-r--r--compiler/pipelines.nim13
-rw-r--r--compiler/pragmas.nim56
-rw-r--r--compiler/pushpoppragmas.nim54
-rw-r--r--compiler/renderer.nim9
-rw-r--r--compiler/reorder.nim26
-rw-r--r--compiler/sem.nim83
-rw-r--r--compiler/semcall.nim173
-rw-r--r--compiler/semdata.nim6
-rw-r--r--compiler/semexprs.nim442
-rw-r--r--compiler/semfold.nim19
-rw-r--r--compiler/semgnrc.nim101
-rw-r--r--compiler/seminst.nim47
-rw-r--r--compiler/semmacrosanity.nim1
-rw-r--r--compiler/semmagic.nim22
-rw-r--r--compiler/semobjconstr.nim11
-rw-r--r--compiler/sempass2.nim16
-rw-r--r--compiler/semstmts.nim238
-rw-r--r--compiler/semtempl.nim102
-rw-r--r--compiler/semtypes.nim192
-rw-r--r--compiler/semtypinst.nim123
-rw-r--r--compiler/sighashes.nim8
-rw-r--r--compiler/sigmatch.nim490
-rw-r--r--compiler/sizealignoffsetimpl.nim7
-rw-r--r--compiler/spawn.nim16
-rw-r--r--compiler/suggest.nim5
-rw-r--r--compiler/transf.nim53
-rw-r--r--compiler/typeallowed.nim11
-rw-r--r--compiler/types.nim173
-rw-r--r--compiler/varpartitions.nim30
-rw-r--r--compiler/vm.nim89
-rw-r--r--compiler/vmdeps.nim15
-rw-r--r--compiler/vmgen.nim143
-rw-r--r--compiler/vmops.nim5
-rw-r--r--config/config.nims2
-rw-r--r--config/nimdoc.cfg7
-rw-r--r--doc/manual.md62
-rw-r--r--doc/manual_experimental.md83
-rw-r--r--doc/nimc.md22
-rw-r--r--doc/nimdoc.css9
-rw-r--r--doc/nims.md33
-rw-r--r--doc/tut2.md2
-rw-r--r--doc/tut3.md30
-rw-r--r--koch.nim19
-rw-r--r--lib/core/macros.nim6
-rw-r--r--lib/core/typeinfo.nim17
-rw-r--r--lib/js/asyncjs.nim4
-rw-r--r--lib/nimbase.h28
-rw-r--r--lib/packages/docutils/rst.nim7
-rw-r--r--lib/posix/inotify.nim34
-rw-r--r--lib/posix/posix_macos_amd64.nim18
-rw-r--r--lib/posix/posix_openbsd_amd64.nim18
-rw-r--r--lib/pure/asyncnet.nim4
-rw-r--r--lib/pure/complex.nim21
-rw-r--r--lib/pure/concurrency/atomics.nim68
-rw-r--r--lib/pure/concurrency/cpuinfo.nim141
-rw-r--r--lib/pure/distros.nim5
-rw-r--r--lib/pure/fenv.nim2
-rw-r--r--lib/pure/hashes.nim228
-rw-r--r--lib/pure/httpcore.nim3
-rw-r--r--lib/pure/includes/unicode_ranges.nim3905
-rw-r--r--lib/pure/ioselects/ioselectors_kqueue.nim8
-rw-r--r--lib/pure/ioselects/ioselectors_select.nim2
-rw-r--r--lib/pure/json.nim2
-rw-r--r--lib/pure/lexbase.nim8
-rw-r--r--lib/pure/logging.nim11
-rw-r--r--lib/pure/math.nim77
-rw-r--r--lib/pure/md5.nim19
-rw-r--r--lib/pure/memfiles.nim68
-rw-r--r--lib/pure/mimetypes.nim4
-rw-r--r--lib/pure/nativesockets.nim2
-rw-r--r--lib/pure/net.nim8
-rw-r--r--lib/pure/options.nim12
-rw-r--r--lib/pure/os.nim11
-rw-r--r--lib/pure/osproc.nim160
-rw-r--r--lib/pure/parseopt.nim18
-rw-r--r--lib/pure/parseutils.nim20
-rw-r--r--lib/pure/pegs.nim4
-rw-r--r--lib/pure/random.nim45
-rw-r--r--lib/pure/streams.nim15
-rw-r--r--lib/pure/strmisc.nim15
-rw-r--r--lib/pure/strutils.nim28
-rw-r--r--lib/pure/sugar.nim6
-rw-r--r--lib/pure/times.nim13
-rw-r--r--lib/pure/typetraits.nim34
-rw-r--r--lib/pure/unicode.nim12
-rw-r--r--lib/pure/volatile.nim12
-rw-r--r--lib/std/enumutils.nim8
-rw-r--r--lib/std/formatfloat.nim6
-rw-r--r--lib/std/paths.nim12
-rw-r--r--lib/std/private/jsutils.nim6
-rw-r--r--lib/std/private/osdirs.nim21
-rw-r--r--lib/std/private/osfiles.nim2
-rw-r--r--lib/std/private/ospaths2.nim6
-rw-r--r--lib/std/private/ossymlinks.nim18
-rw-r--r--lib/std/syncio.nim2
-rw-r--r--lib/std/tasks.nim24
-rw-r--r--lib/std/time_t.nim2
-rw-r--r--lib/std/varints.nim12
-rw-r--r--lib/system.nim40
-rw-r--r--lib/system/alloc.nim227
-rw-r--r--lib/system/arithmetics.nim8
-rw-r--r--lib/system/comparisons.nim2
-rw-r--r--lib/system/compilation.nim2
-rw-r--r--lib/system/hti.nim2
-rw-r--r--lib/system/indices.nim13
-rw-r--r--lib/system/jssys.nim31
-rw-r--r--lib/system/nimscript.nim17
-rw-r--r--lib/system/orc.nim34
-rw-r--r--lib/system/reprjs.nim4
-rw-r--r--lib/system/seqs_v2.nim6
-rw-r--r--lib/system/strs_v2.nim2
-rw-r--r--lib/system/sysstr.nim10
-rw-r--r--nimdoc/extlinks/project/expected/_._/util.html7
-rw-r--r--nimdoc/extlinks/project/expected/doc/manual.html7
-rw-r--r--nimdoc/extlinks/project/expected/main.html7
-rw-r--r--nimdoc/extlinks/project/expected/sub/submodule.html7
-rw-r--r--nimdoc/extlinks/project/expected/theindex.html7
-rw-r--r--nimdoc/rst2html/expected/rst_examples.html7
-rw-r--r--nimdoc/test_doctype/expected/test_doctype.html10
-rw-r--r--nimdoc/test_out_index_dot_html/expected/index.html7
-rw-r--r--nimdoc/test_out_index_dot_html/expected/theindex.html7
-rw-r--r--nimdoc/testproject/expected/nimdoc.out.css9
-rw-r--r--nimdoc/testproject/expected/subdir/subdir_b/utils.html7
-rw-r--r--nimdoc/testproject/expected/testproject.html7
-rw-r--r--nimdoc/testproject/expected/theindex.html7
-rw-r--r--nimpretty/nimpretty.nim8
-rw-r--r--nimsuggest/nimsuggest.nim37
-rw-r--r--nimsuggest/tests/tarrowcrash.nim20
-rw-r--r--nimsuggest/tests/tchk2.nim35
-rw-r--r--nimsuggest/tests/tgeneric_highlight.nim5
-rw-r--r--testament/important_packages.nim25
-rw-r--r--testament/lib/stdtest/testutils.nim5
-rw-r--r--testament/testament.nim27
-rw-r--r--tests/alloc/tmembug.nim54
-rw-r--r--tests/alloc/tmembug2.nim58
-rw-r--r--tests/arc/tarc_orc.nim49
-rw-r--r--tests/arc/tarcmisc.nim117
-rw-r--r--tests/arc/tcaseobj.nim26
-rw-r--r--tests/arc/titeration_doesnt_copy.nim11
-rw-r--r--tests/arc/topenarray.nim16
-rw-r--r--tests/arc/tstringliteral.nim17
-rw-r--r--tests/async/tioselectors.nim21
-rw-r--r--tests/c/temit.nim1
-rw-r--r--tests/casestmt/tcase_issues.nim7
-rw-r--r--tests/casestmt/tcasestmt.nim5
-rw-r--r--tests/casestmt/trangeexhaustiveness.nim7
-rw-r--r--tests/ccgbugs/t10964.nim3
-rw-r--r--tests/ccgbugs/t13062.nim7
-rw-r--r--tests/ccgbugs/t20141.nim4
-rw-r--r--tests/ccgbugs/t23796.nim25
-rw-r--r--tests/ccgbugs/tcgbug.nim28
-rw-r--r--tests/ccgbugs/tsamename3.nim9
-rw-r--r--tests/closure/t8550.nim1
-rw-r--r--tests/closure/tnested.nim35
-rw-r--r--tests/codegen/titaniummangle.nim9
-rw-r--r--tests/compileoption/texperimental.nim20
-rw-r--r--tests/compileoption/texperimental.nims19
-rw-r--r--tests/concepts/tusertypeclasses2.nim16
-rw-r--r--tests/config.nims4
-rw-r--r--tests/controlflow/tunreachable2.nim12
-rw-r--r--tests/cpp/23962.h17
-rw-r--r--tests/cpp/fam.h4
-rw-r--r--tests/cpp/t23657.nim54
-rw-r--r--tests/cpp/t23962.nim32
-rw-r--r--tests/cpp/tcasts.nim3
-rw-r--r--tests/cpp/tfam.nim7
-rw-r--r--tests/destructor/t23748.nim31
-rw-r--r--tests/destructor/t23837.nim51
-rw-r--r--tests/destructor/tatomicptrs.nim2
-rw-r--r--tests/destructor/tdistinctseq.nim8
-rw-r--r--tests/destructor/tgotoexc_leak.nim19
-rw-r--r--tests/destructor/tmove_objconstr.nim35
-rw-r--r--tests/destructor/tsink.nim54
-rw-r--r--tests/destructor/tv2_cast.nim58
-rw-r--r--tests/discard/t23677.nim12
-rw-r--r--tests/discard/tdiscardable.nim63
-rw-r--r--tests/discard/tfinallyerrmsg.nim19
-rw-r--r--tests/distinct/tcomplexaddressableconv.nim21
-rw-r--r--tests/enum/tenum.nim81
-rw-r--r--tests/enum/tenum_duplicate.nim10
-rw-r--r--tests/enum/toverloadedname.nim7
-rw-r--r--tests/enum/tpure_enums_conflict.nim15
-rw-r--r--tests/enum/tpure_enums_conflict_legacy.nim25
-rw-r--r--tests/enum/ttypenameconflict.nim13
-rw-r--r--tests/errmsgs/mambparam1.nim1
-rw-r--r--tests/errmsgs/mambparam2.nim2
-rw-r--r--tests/errmsgs/mambparam3.nim1
-rw-r--r--tests/errmsgs/t10735.nim60
-rw-r--r--tests/errmsgs/t22097.nim4
-rw-r--r--tests/errmsgs/t22753.nim45
-rw-r--r--tests/errmsgs/t22852.nim9
-rw-r--r--tests/errmsgs/t23419.nim5
-rw-r--r--tests/errmsgs/t23536.nim26
-rw-r--r--tests/errmsgs/tambparam.nim16
-rw-r--r--tests/errmsgs/tambparam_legacy.nim14
-rw-r--r--tests/errmsgs/tconcisetypemismatch.nim2
-rw-r--r--tests/errmsgs/tconcisetypemismatch.nims21
-rw-r--r--tests/errmsgs/tgenericmismatchsegfault.nim13
-rw-r--r--tests/errmsgs/tgenericmismatchsegfault_legacy.nim10
-rw-r--r--tests/errmsgs/tinconsistentgensym.nim2
-rw-r--r--tests/errmsgs/tmetaobjectfields.nim75
-rw-r--r--tests/errmsgs/tsubscriptmismatch.nim11
-rw-r--r--tests/errmsgs/tsubscriptmismatch_legacy.nim10
-rw-r--r--tests/errmsgs/tundeclared_routine.nim2
-rw-r--r--tests/errmsgs/tuntypedoverload.nim37
-rw-r--r--tests/errmsgs/twrong_explicit_typeargs.nim26
-rw-r--r--tests/errmsgs/twrong_explicit_typeargs_legacy.nim25
-rw-r--r--tests/generics/mopensymimport1.nim34
-rw-r--r--tests/generics/mopensymimport2.nim16
-rw-r--r--tests/generics/t19848.nim16
-rw-r--r--tests/generics/t23790.nim14
-rw-r--r--tests/generics/t23853.nim91
-rw-r--r--tests/generics/t23854.nim71
-rw-r--r--tests/generics/t23855.nim61
-rw-r--r--tests/generics/taliashijack.nim8
-rw-r--r--tests/generics/tbadcache.nim26
-rw-r--r--tests/generics/tbracketinstantiation.nim86
-rw-r--r--tests/generics/tcalltype.nim26
-rw-r--r--tests/generics/tgeneric0.nim8
-rw-r--r--tests/generics/tgenericwhen.nim58
-rw-r--r--tests/generics/tgensyminst.nim29
-rw-r--r--tests/generics/timplicit_and_explicit.nim4
-rw-r--r--tests/generics/tmacroinjectedsym.nim73
-rw-r--r--tests/generics/tmacroinjectedsymwarning.nim11
-rw-r--r--tests/generics/tnestedissues.nim24
-rw-r--r--tests/generics/tnestedtemplate.nim9
-rw-r--r--tests/generics/topensymimport.nim5
-rw-r--r--tests/generics/tstatic_constrained.nim6
-rw-r--r--tests/generics/tuninstantiatedgenericcalls.nim375
-rw-r--r--tests/generics/twrong_explicit_typeargs.nim16
-rw-r--r--tests/generics/twrong_generic_object.nim4
-rw-r--r--tests/int/t1.nim47
-rw-r--r--tests/int/tints.nim4
-rw-r--r--tests/int/tunsignedinc.nim6
-rw-r--r--tests/int/twrongexplicitvarconv.nim16
-rw-r--r--tests/int/twrongvarconv.nim9
-rw-r--r--tests/iter/t1550.nim4
-rw-r--r--tests/iter/t21306.nim4
-rw-r--r--tests/iter/t2771.nim4
-rw-r--r--tests/iter/tanoniter1.nim1
-rw-r--r--tests/iter/tclosureiters.nim22
-rw-r--r--tests/iter/titer11.nim1
-rw-r--r--tests/iter/titer12.nim1
-rw-r--r--tests/iter/titer_issues.nim17
-rw-r--r--tests/iter/tyieldintry.nim25
-rw-r--r--tests/js/t7109.nim3
-rw-r--r--tests/js/tdanger.nim17
-rw-r--r--tests/js/tjsffi.nim1
-rw-r--r--tests/js/tjsnimscombined.nim1
-rw-r--r--tests/js/tjsnimscombined.nims1
-rw-r--r--tests/js/ttypedarray.nim2
-rw-r--r--tests/lent/tlent_from_var.nim55
-rw-r--r--tests/lent/tvm.nim21
-rw-r--r--tests/lookups/mambtype1.nim1
-rw-r--r--tests/lookups/mambtype2.nim4
-rw-r--r--tests/lookups/mdisambsym1.nim2
-rw-r--r--tests/lookups/mdisambsym2.nim1
-rw-r--r--tests/lookups/mdisambsym3.nim1
-rw-r--r--tests/lookups/mmacroamb.nim10
-rw-r--r--tests/lookups/t23749.nim37
-rw-r--r--tests/lookups/tambtype.nim20
-rw-r--r--tests/lookups/tdisambsym.nim8
-rw-r--r--tests/lookups/tenumlocalsym.nim22
-rw-r--r--tests/lookups/tmacroamb.nim5
-rw-r--r--tests/lookups/tmoduleclash1.nim13
-rw-r--r--tests/lookups/tmoduleclash2.nim6
-rw-r--r--tests/macros/t23547.nim23
-rw-r--r--tests/macros/t23784.nim157
-rw-r--r--tests/macros/tastrepr.nim7
-rw-r--r--tests/macros/tgettypeinst7737.nim61
-rw-r--r--tests/macros/tmacrotypes.nim6
-rw-r--r--tests/macros/tprocgettype.nim28
-rw-r--r--tests/metatype/tmetatype_issues.nim9
-rw-r--r--tests/metatype/ttypedescnotnimnode.nim21
-rw-r--r--tests/metatype/ttypeselectors.nim13
-rw-r--r--tests/metatype/ttypetraits.nim37
-rw-r--r--tests/metatype/twrong_same_type.nim28
-rw-r--r--tests/misc/mjsondoc.nim3
-rw-r--r--tests/misc/t20883.nim7
-rw-r--r--tests/misc/tcast.nim7
-rw-r--r--tests/misc/tconv.nim7
-rw-r--r--tests/misc/trunner.nim6
-rw-r--r--tests/misc/trunner_special.nim7
-rw-r--r--tests/misc/tsizeof.nim8
-rw-r--r--tests/modules/mincludeprefix.nim1
-rw-r--r--tests/modules/mincludetemplate.nim1
-rw-r--r--tests/modules/tincludeprefix.nim3
-rw-r--r--tests/modules/tincludetemplate.nim5
-rw-r--r--tests/modules/treorder.nim4
-rw-r--r--tests/msgs/tused2.nim8
-rw-r--r--tests/niminaction/Chapter8/sdl/sdl_test.nim2
-rw-r--r--tests/objects/tobject_default_value.nim35
-rw-r--r--tests/objects/trequireinit.nim10
-rw-r--r--tests/openarray/topenarray.nim35
-rw-r--r--tests/openarray/tuncheckedarray.nim19
-rw-r--r--tests/osproc/tnoexe.nim27
-rw-r--r--tests/osproc/twaitforexit.nim38
-rw-r--r--tests/overload/m19737.nim10
-rw-r--r--tests/overload/mvaruintconv.nim145
-rw-r--r--tests/overload/t19737.nim15
-rw-r--r--tests/overload/t23755.nim62
-rw-r--r--tests/overload/t8829.nim4
-rw-r--r--tests/overload/tgenericalias.nim13
-rw-r--r--tests/overload/tor_isnt_better.nim23
-rw-r--r--tests/overload/toverload_issues.nim45
-rw-r--r--tests/overload/toverload_various.nim60
-rw-r--r--tests/overload/tuntypedarg.nim19
-rw-r--r--tests/overload/tvaruintconv.nim207
-rw-r--r--tests/parallel/tsendtwice.nim21
-rw-r--r--tests/parser/tbinarynotindented.nim3
-rw-r--r--tests/parser/tbinarynotsameline.nim10
-rw-r--r--tests/pragmas/mqualifiedmacro.nim10
-rw-r--r--tests/pragmas/tcustom_pragma.nim7
-rw-r--r--tests/pragmas/tpush.nim43
-rw-r--r--tests/pragmas/tpushnotes.nim13
-rw-r--r--tests/pragmas/tqualifiedmacro.nim14
-rw-r--r--tests/proc/t23874.nim26
-rw-r--r--tests/proc/texplicitgenericcount.nim24
-rw-r--r--tests/proc/texplicitgenericcountverbose.nim22
-rw-r--r--tests/proc/texplicitgenerics.nim55
-rw-r--r--tests/proc/tgenericdefaultparam.nim98
-rw-r--r--tests/proc/tstaticsignature.nim268
-rw-r--r--tests/proc/twrongdefaultvalue.nim25
-rw-r--r--tests/range/tcompiletime_range_checks.nim4
-rw-r--r--tests/range/texplicitvarconv.nim13
-rw-r--r--tests/range/toutofrangevarconv.nim14
-rw-r--r--tests/refc/tsinkbug.nim26
-rw-r--r--tests/sets/trangeincompatible.nim32
-rw-r--r--tests/sets/twrongenumrange.nim50
-rw-r--r--tests/stdlib/concurrency/tatomics.nim4
-rw-r--r--tests/stdlib/concurrency/tatomics_size.nim5
-rw-r--r--tests/stdlib/tcomplex.nim3
-rw-r--r--tests/stdlib/tenumutils.nim10
-rw-r--r--tests/stdlib/thashes.nim29
-rw-r--r--tests/stdlib/thttpclient.nim12
-rw-r--r--tests/stdlib/thttpclient_ssl.nim5
-rw-r--r--tests/stdlib/tjson.nim4
-rw-r--r--tests/stdlib/tmarshalsegfault.nim54
-rw-r--r--tests/stdlib/tmimetypes.nim5
-rw-r--r--tests/stdlib/tos.nim15
-rw-r--r--tests/stdlib/tparseutils.nim11
-rw-r--r--tests/stdlib/tpaths.nim14
-rw-r--r--tests/stdlib/trandom.nim14
-rw-r--r--tests/stdlib/trst.nim27
-rw-r--r--tests/stdlib/trstgen.nim2
-rw-r--r--tests/stdlib/tstreams.nim4
-rw-r--r--tests/stdlib/tstrutils.nim4
-rw-r--r--tests/stdlib/tsystem.nim52
-rw-r--r--tests/stdlib/ttasks.nim36
-rw-r--r--tests/stdlib/ttimes.nim16
-rw-r--r--tests/stdlib/ttypeinfo.nim17
-rw-r--r--tests/stdlib/tunicode.nim2
-rw-r--r--tests/stdlib/tunixsocket.nim35
-rw-r--r--tests/stdlib/tvarints.nim2
-rw-r--r--tests/stdlib/tvolatile.nim15
-rw-r--r--tests/stdlib/twrongstattype.nim14
-rw-r--r--tests/stdlib/unixsockettest.nim26
-rw-r--r--tests/system/tdollars.nim8
-rw-r--r--tests/system/tsystem_misc.nim6
-rw-r--r--tests/template/m19277_1.nim2
-rw-r--r--tests/template/m19277_2.nim2
-rw-r--r--tests/template/mqualifiedtype1.nim2
-rw-r--r--tests/template/mqualifiedtype2.nim2
-rw-r--r--tests/template/t13426.nim87
-rw-r--r--tests/template/t19277.nim19
-rw-r--r--tests/template/t24112.nim19
-rw-r--r--tests/template/tdefaultparam.nim56
-rw-r--r--tests/template/tinnerouterproc.nim12
-rw-r--r--tests/template/topensym.nim209
-rw-r--r--tests/template/topensymoverride.nim39
-rw-r--r--tests/template/topensymwarning.nim60
-rw-r--r--tests/template/tqualifiedtype.nim25
-rw-r--r--tests/threads/tmembug.nim51
-rw-r--r--tests/tools/tunused_imports.nim11
-rw-r--r--tests/trmacros/tor.nim6
-rw-r--r--tests/trmacros/trmacros_various2.nim4
-rw-r--r--tests/typerel/tuncheckedarray_eq.nim2
-rw-r--r--tests/types/tinheritgenericparameter.nim4
-rw-r--r--tests/types/tisopr.nim4
-rw-r--r--tests/types/ttopdowninference.nim6
-rw-r--r--tests/varres/tprevent_forloopvar_mutations.nim2
-rw-r--r--tests/views/tviews1.nim10
-rw-r--r--tests/views/tviews2.nim90
-rw-r--r--tests/vm/tconstarrayresem.nim29
-rw-r--r--tests/vm/tconstscope1.nim5
-rw-r--r--tests/vm/tconstscope2.nim5
-rw-r--r--tests/vm/tconsttable.nim15
-rw-r--r--tests/vm/tconvaddr.nim49
-rw-r--r--tests/vm/tgenericcompiletimeproc.nim36
-rw-r--r--tests/vm/tnilclosurecall.nim8
-rw-r--r--tests/vm/tnilclosurecallstacktrace.nim23
-rw-r--r--tests/vm/topenarrays.nim20
-rw-r--r--tests/vm/tvmmisc.nim32
-rw-r--r--tests/vm/tvmopsDanger.nim7
-rw-r--r--tools/debug/nim-gdb.py10
-rw-r--r--tools/dochack/dochack.nim4
-rw-r--r--tools/kochdocs.nim5
-rw-r--r--tools/niminst/buildsh.nimf1
-rw-r--r--tools/niminst/makefile.nimf1
-rw-r--r--tools/unicode_parsedata.nim70
464 files changed, 13476 insertions, 11948 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 014513865..1e46e0544 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -7,17 +7,16 @@ body:
 - type: markdown
   attributes:
     value: |
-      - **Please provide a minimal code example that reproduces the Bug!** :bug:
-        Reports with a reproducible example and descriptive detailed information will likely receive fixes faster.
+      Please provide a minimal code example that reproduces the bug if possible.
+      Reports with a reproducible example or detailed information will likely receive fixes faster.
 
 - type: textarea
   id: description
   attributes:
     label: Description
     description: |
-      Use DETAILED DESCRIPTIVE information about the problem.
-      Here, you go into more details about your Bug report. This section can be a few paragraphs long.
-    placeholder: Bug reports with reproducible code and detailed information will be fixed faster.
+      Describe the problem. Code example can be given here.
+    placeholder: Bug reports with reproducible code or detailed information will be fixed faster.
   validations:
     required: true
     
@@ -25,7 +24,9 @@ body:
   id: nim-version
   attributes:
     label: Nim Version
-    description: Copy and paste the output of `nim -v` on the command line. For development versions, make sure to include the commit hash.
+    description: |
+      Can be obtained from `nim -v` on the command line along with the OS/architecture.
+      For development versions, make sure to include the commit hash.
   validations:
     required: true
 
@@ -34,7 +35,7 @@ body:
   attributes:
     label: Current Output
     description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
-    placeholder: Bug reports with reproducible code and detailed information will be fixed faster.
+    placeholder: Bug reports with reproducible code or detailed information will be fixed faster.
     render: text
 
 - type: textarea
@@ -42,14 +43,14 @@ body:
   attributes:
     label: Expected Output
     description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
-    placeholder: Bug reports with reproducible code and detailed information will be fixed faster.
+    placeholder: Bug reports with reproducible code or detailed information will be fixed faster.
     render: text
 
 - type: textarea
-  id: possible-solution
+  id: known-workarounds
   attributes:
-    label: Possible Solution
-    description: Propose a possible solution.
+    label: Known Workarounds
+    description: Provide any known workarounds.
   validations:
     required: false
 
@@ -64,13 +65,9 @@ body:
 - type: markdown
   attributes:
     value: |
-      - Thanks for your contributions!, your Bug report will receive feedback from the community soon...
-      - Please check whether the problem still exists in the devel branch, see [rebuilding the compiler](https://nim-lang.github.io/Nim/intern.html#rebuilding-the-compiler).
+      - Please check whether the problem still exists in the devel branch, which can be installed via [choosenim](https://github.com/nim-lang/choosenim/), [nightlies](https://github.com/nim-lang/nightlies/), or by [creating a temporary build of the compiler](https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler-building-an-instrumented-compiler).
       - Consider writing a PR targetting devel branch after filing this, see [contributing](https://nim-lang.github.io/Nim/contributing.html).
-      - If it's a pre-existing compiler bug, see [Debugging the compiler](https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler)
-        which should give more context on a compiler crash.
-      - If it's a regression, you can help us by identifying which version introduced the bug,
-        see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions),
-        or at least try known past releases (e.g. `choosenim 2.0.0`). The Nim repo also supports online bisecting
-        via making a comment, which contains a code block starting by `!nim c`, `!nim js` etc. , see [nimrun-action](https://github.com/juancarlospaco/nimrun-action).
+      - If it's a pre-existing compiler bug, see [debugging the compiler](https://nim-lang.github.io/Nim/intern.html#debugging-the-compiler) which should give more context on a compiler crash.
+      - If it's a regression, you can help us by identifying which version introduced the bug by [bisecting](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions) or at least trying known past releases (e.g. `choosenim 2.0.0`).
+        The Nim repo also supports bisecting in issue comments by adding `!nim c`, `!nim js` etc. before a code block, see [nimrun-action](https://github.com/juancarlospaco/nimrun-action).
       - [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html)
diff --git a/.github/workflows/ci_bench.yml b/.github/workflows/ci_bench.yml
deleted file mode 100644
index 7c76ed89b..000000000
--- a/.github/workflows/ci_bench.yml
+++ /dev/null
@@ -1,115 +0,0 @@
-name: Benchmarks CI
-on:
-  pull_request:
-  push:
-    branches:
-      - 'devel'
-
-jobs:
-  build:
-    strategy:
-      fail-fast: false
-      matrix:
-        os: [ubuntu-20.04]
-        cpu: [amd64]
-    name: '${{ matrix.os }}'
-    runs-on: ${{ matrix.os }}
-    timeout-minutes: 60 # refs bug #18178
-    steps:
-      - name: 'Checkout'
-        uses: actions/checkout@v4
-        with:
-          fetch-depth: 2
-
-      - name: 'Install node.js 20.x'
-        uses: actions/setup-node@v4
-        with:
-          node-version: '20.x'
-
-      - name: 'Install dependencies (Linux amd64)'
-        if: runner.os == 'Linux' && matrix.cpu == 'amd64'
-        run: |
-          sudo apt-fast update -qq
-          DEBIAN_FRONTEND='noninteractive' \
-            sudo apt-fast install --no-install-recommends -yq \
-              libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
-              valgrind libc6-dbg libblas-dev xorg-dev
-
-      - name: 'Add build binaries to PATH'
-        shell: bash
-        run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
-
-      - name: 'Build csourcesAny'
-        shell: bash
-        run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
-
-      - name: 'Build koch'
-        shell: bash
-        run: nim c koch
-
-      - name: 'Build Nim'
-        shell: bash
-        run: ./koch boot -d:release -d:nimStrictMode --lib:lib
-
-      - name: 'Build Nimble'
-        shell: bash
-        run: ./koch nimble
-
-      - name: 'Action'
-        shell: bash
-        run: nim c -r -d:release ci/action.nim
-
-      - name: 'Checkout minimize'
-        uses: actions/checkout@v4
-        with:
-          repository: 'nim-lang/ci_bench'
-          path: minimize
-
-      - name: 'Run minimize benchmarks'
-        shell: bash
-        run: ./minimize/minimize ci-bench
-
-      - name: 'Restore minimize cached database'
-        uses: actions/cache/restore@v3
-        with:
-          path: minimize.csv
-          key: minimize-db-key
-
-      - name: 'Update minimize db'
-        shell: bash
-        run: ./minimize/minimize update-db
-
-      - name: 'Save minimize cached database'
-        if: |
-          github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
-          matrix.target == 'linux'
-        uses: actions/cache/save@v3
-        with:
-          path: minimize.csv
-          key: minimize-db-key
-
-      - name: 'Generate minimize report'
-        shell: bash
-        run: ./minimize/minimize generate-report
-
-      - name: 'Archive minimize report'
-        uses: actions/upload-artifact@v3
-        with:
-          name: minimize-report
-          path: |
-            minimize/minimize.html
-            minimize/minimize.csv
-
-      # Requires additional permissions, see:
-      # https://github.com/nim-lang/Nim/actions/runs/4778177321/jobs/8494423792?pr=21566
-      # - name: 'Publish HTML report'
-      #   uses: rossjrw/pr-preview-action@v1
-      #   with:
-      #     source-dir: minimize
-      #     umbrella-dir: minimize
-      #   env:
-      #     GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
-      - name: Extract md summary
-        run: |
-          cat minimize/summary.md  >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/ci_gcc14.yml b/.github/workflows/ci_gcc14.yml
new file mode 100644
index 000000000..fb286887a
--- /dev/null
+++ b/.github/workflows/ci_gcc14.yml
@@ -0,0 +1,76 @@
+name: GCC 14
+on:
+  pull_request:
+  push:
+    branches:
+      - 'devel'
+
+
+jobs:
+  build:
+    strategy:
+      fail-fast: false
+      matrix:
+        os: [ubuntu-24.04]
+        cpu: [amd64]
+    name: '${{ matrix.os }}'
+    runs-on: ${{ matrix.os }}
+    timeout-minutes: 60 # refs bug #18178
+    steps:
+      - name: 'Checkout'
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 2
+
+      - name: 'Install node.js 20.x'
+        uses: actions/setup-node@v4
+        with:
+          node-version: '20.x'
+
+      - name: 'Install dependencies (Linux amd64)'
+        if: runner.os == 'Linux' && matrix.cpu == 'amd64'
+        run: |
+          sudo apt update -qq
+          sudo apt remove needrestart
+          DEBIAN_FRONTEND='noninteractive' \
+            sudo apt install --no-install-recommends -yq \
+              libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
+              valgrind libc6-dbg libblas-dev xorg-dev
+      - name: 'Install dependencies (Linux amd64 gcc 14)'
+        if: runner.os == 'Linux' && matrix.cpu == 'amd64'
+        run: |
+          sudo add-apt-repository universe
+          sudo apt update -qq
+          sudo apt install -y gcc-14 g++-14 libpcre3 liblapack-dev
+          sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 60 --slave /usr/bin/g++ g++ /usr/bin/g++-14
+      - name: 'Install dependencies (macOS)'
+        if: runner.os == 'macOS'
+        run: brew install boehmgc make sfml gtk+3
+      - name: 'Install dependencies (Windows)'
+        if: runner.os == 'Windows'
+        shell: bash
+        run: |
+          set -e
+          . ci/funs.sh
+          nimInternalInstallDepsWindows
+          echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
+
+      - name: 'Add build binaries to PATH'
+        shell: bash
+        run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
+
+      - name: 'NIM_TESTAMENT_DISABLE_SSL'
+        shell: bash
+        run: echo "NIM_TESTAMENT_DISABLE_SSL=1" >> $GITHUB_ENV
+
+      - name: 'System information'
+        shell: bash
+        run: . ci/funs.sh && nimCiSystemInfo
+
+      - name: 'Build csourcesAny'
+        shell: bash
+        run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
+
+      - name: 'koch, Run CI'
+        shell: bash
+        run: . ci/funs.sh && nimInternalBuildKochAndRunCI
diff --git a/changelog.md b/changelog.md
index c010714fa..8acd2120a 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,109 +1,18 @@
-# v2.2.0 - yyyy-mm-dd
+# v2.x.x - yyyy-mm-dd
 
 
 ## Changes affecting backward compatibility
 
-- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility.
-- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
-- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to be in the same module where their type has been defined.
-- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
-- A bug where tuple unpacking assignment with a longer tuple on the RHS than the LHS was allowed has been fixed, i.e. code like:
-  ```nim
-  var a, b: int
-  (a, b) = (1, 2, 3, 4)
-  ```
-  will no longer compile.
-- `internalNew` is removed from system, use `new` instead.
-
-- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures.
 
 ## Standard library additions and changes
 
-[//]: # "Changes:"
-
-- Changed `std/osfiles.copyFile` to allow to specify `bufferSize` instead of a hardcoded one.
-- Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads.
-- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it.
-
-[//]: # "Additions:"
-
-- Added `newStringUninit` to system, which creates a new string of length `len` like `newString` but with uninitialized content.
-- Added `setLenUninit` to system, which doesn't initalize
-slots when enlarging a sequence.
-- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
-- Added Viewport API for the JavaScript targets in the `dom` module.
-- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s.
-- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many
-  objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
-  instead of `--mm:orc`.
-
-[//]: # "Deprecations:"
-
-- Deprecates `system.newSeqUninitialized`, which is replaced by `newSeqUninit`.
-
-[//]: # "Removals:"
-
 
 ## Language changes
 
-- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
-- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.htm#constructor-initializer
-- `member` can be used to attach a procedure to a C++ type.
-- C++ `constructor` now reuses `result` instead creating `this`.
-
-- Tuple unpacking changes:
-  - Tuple unpacking assignment now supports using underscores to discard values.
-    ```nim
-    var a, c: int
-    (a, _, c) = (1, 2, 3)
-    ```
-  - Tuple unpacking variable declarations now support type annotations, but
-    only for the entire tuple.
-    ```nim
-    let (a, b): (int, int) = (1, 2)
-    let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc"))
-    ```
-
-- An experimental option `genericsOpenSym` has been added to allow captured
-  symbols in generic routine bodies to be replaced by symbols injected locally
-  by templates/macros at instantiation time. `bind` may be used to keep the
-  captured symbols over the injected ones regardless of enabling the option.
-
-  Since this change may affect runtime behavior, the experimental switch
-  `genericsOpenSym` needs to be enabled, and a warning is given in the case
-  where an injected symbol would replace a captured symbol not bound by `bind`
-  and the experimental switch isn't enabled.
-
-  ```nim
-  const value = "captured"
-  template foo(x: int, body: untyped) =
-    let value {.inject.} = "injected"
-    body
-
-  proc old[T](): string =
-    foo(123):
-      return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:genericsOpenSym`
-  echo old[int]() # "captured"
-
-  {.experimental: "genericsOpenSym".}
-
-  proc bar[T](): string =
-    foo(123):
-      return value
-  assert bar[int]() == "injected" # previously it would be "captured"
-
-  proc baz[T](): string =
-    bind value
-    foo(123):
-      return value
-  assert baz[int]() == "captured"
-  ```
 
 ## Compiler changes
 
-- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.
 
 ## Tool changes
 
-- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow.
 
diff --git a/changelogs/changelog_2_2_0.md b/changelogs/changelog_2_2_0.md
index 0a293d35f..b50cbeb27 100644
--- a/changelogs/changelog_2_2_0.md
+++ b/changelogs/changelog_2_2_0.md
@@ -1,12 +1,248 @@
-# v2.2.0 - 2023-mm-dd
+# v2.2.0 - 2024-10-02
+
 
 ## Changes affecting backward compatibility
 
+- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` is out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backward compatibility.
+
+- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
+
+- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to the same module where their type has been defined.
+
+- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
+
+- A bug where tuple unpacking assignment with a longer tuple on the RHS than the LHS was allowed has been fixed, i.e. code like:
+  ```nim
+  var a, b: int
+  (a, b) = (1, 2, 3, 4)
+  ```
+  will no longer compile.
+
+- `internalNew` is removed from the `system` module, use `new` instead.
+
+- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures.
+
+- JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behaviors.
+
+- JS backend now supports closure iterators.
+
+- `owner` in `std/macros` is deprecated.
+
+- Ambiguous type symbols in generic procs and templates now generate symchoice nodes.
+  Previously; in templates they would error immediately at the template definition,
+  and in generic procs a type symbol would arbitrarily be captured, losing the
+  information of the other symbols. This means that generic code can now give
+  errors for ambiguous type symbols, and macros operating on generic proc AST
+  may encounter symchoice nodes instead of the arbitrarily resolved type symbol nodes.
+
+- Partial generic instantiation of routines is no longer allowed. Previously
+  it compiled in niche situations due to bugs in the compiler.
+
+  ```nim
+  proc foo[T, U](x: T, y: U) = echo (x, y)
+  proc foo[T, U](x: var T, y: U) = echo "var ", (x, y)
+
+  proc bar[T]() =
+    foo[float](1, "abc")
+
+  bar[int]() # before: (1.0, "abc"), now: type mismatch, missing generic parameter
+  ```
+
+- `const` values now open a new scope for each constant, meaning symbols
+  declared in them can no longer be used outside or in the value of
+  other constants.
+
+  ```nim
+  const foo = (var a = 1; a)
+  const bar = a # error
+  let baz = a # error
+  ```
+
+- The following POSIX wrappers have had their types changed from signed to
+  unsigned types on OSX and FreeBSD/OpenBSD to correct codegen errors:
+  - `Gid` (was `int32`, is now `uint32`)
+  - `Uid` (was `int32`, is now `uint32`)
+  - `Dev` (was `int32`, is now `uint32` on FreeBSD)
+  - `Nlink` (was `int16`, is now `uint32` on OpenBSD and `uint16` on OSX/other BSD)
+  - `sin6_flowinfo` and `sin6_scope_id` fields of `Sockaddr_in6`
+    (were `int32`, are now `uint32`)
+  - `n_net` field of `Tnetent` (was `int32`, is now `uint32`)
+
+- The `Atomic[T]` type on C++ now uses C11 primitives by default instead of
+  `std::atomic`. To use `std::atomic` instead, `-d:nimUseCppAtomics` can be defined.
+
+
+
+
+
+
 ## Standard library additions and changes
 
+[//]: # "Changes:"
+
+- Changed `std/osfiles.copyFile` to allow specifying `bufferSize` instead of a hard-coded one.
+- Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads.
+- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it.
+- Changed `std/os.copyDir` and `copyDirWithPermissions` to allow skipping special "file" objects like FIFOs, device files, etc on Unix by specifying a `skipSpecial` parameter.
+
+[//]: # "Additions:"
+
+- Added `newStringUninit` to the `system` module, which creates a new string of length `len` like `newString` but with uninitialized content.
+- Added `setLenUninit` to the `system` module, which doesn't initialize
+slots when enlarging a sequence.
+- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
+- Added `rangeBase` to `std/typetraits` to obtain the base type of a range type or
+  convert a value with a range type to its base type.
+- Added Viewport API for the JavaScript targets in the `dom` module.
+- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s.
+- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many
+  objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
+  instead of `--mm:orc`.
+- A `$` template is provided for `Path` in `std/paths`.
+- `std/hashes.hash(x:string)` changed to produce a 64-bit string `Hash` (based
+on Google's Farm Hash) which is also often faster than the present one.  Define
+`nimStringHash2` to get the old values back.  `--jsbigint=off` mode always only
+produces the old values.  This may impact your automated tests if they depend
+on hash order in some obvious or indirect way.  Using `sorted` or `OrderedTable`
+is often an easy workaround.
+
+[//]: # "Deprecations:"
+
+- Deprecates `system.newSeqUninitialized`, which is replaced by `newSeqUninit`.
+
+[//]: # "Removals:"
+
+
+
+
+
+
 ## Language changes
 
+- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
+
+- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.html#constructor-initializer
+
+- `member` can be used to attach a procedure to a C++ type.
+
+- C++ `constructor` now reuses `result` instead creating `this`.
+
+- Tuple unpacking changes:
+  - Tuple unpacking assignment now supports using underscores to discard values.
+    ```nim
+    var a, c: int
+    (a, _, c) = (1, 2, 3)
+    ```
+  - Tuple unpacking variable declarations now support type annotations, but
+    only for the entire tuple.
+    ```nim
+    let (a, b): (int, int) = (1, 2)
+    let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc"))
+    ```
+
+- The experimental option `--experimental:openSym` has been added to allow
+  captured symbols in generic routine and template bodies respectively to be
+  replaced by symbols injected locally by templates/macros at instantiation
+  time. `bind` may be used to keep the captured symbols over the injected ones
+  regardless of enabling the option, but other methods like renaming the
+  captured symbols should be used instead so that the code is not affected by
+  context changes.
+
+  Since this change may affect runtime behavior, the experimental switch
+  `openSym` needs to be enabled; and a warning is given in the case where an
+  injected symbol would replace a captured symbol not bound by `bind` and
+  the experimental switch isn't enabled.
+
+  ```nim
+  const value = "captured"
+  template foo(x: int, body: untyped): untyped =
+    let value {.inject.} = "injected"
+    body
+
+  proc old[T](): string =
+    foo(123):
+      return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
+  echo old[int]() # "captured"
+
+  template oldTempl(): string =
+    block:
+      foo(123):
+        value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
+  echo oldTempl() # "captured"
+
+  {.experimental: "openSym".}
+
+  proc bar[T](): string =
+    foo(123):
+      return value
+  assert bar[int]() == "injected" # previously it would be "captured"
+
+  proc baz[T](): string =
+    bind value
+    foo(123):
+      return value
+  assert baz[int]() == "captured"
+
+  template barTempl(): string =
+    block:
+      foo(123):
+        value
+  assert barTempl() == "injected" # previously it would be "captured"
+
+  template bazTempl(): string =
+    bind value
+    block:
+      foo(123):
+        value
+  assert bazTempl() == "captured"
+  ```
+
+  This option also generates a new node kind `nnkOpenSym` which contains
+  exactly 1 `nnkSym` node. In the future this might be merged with a slightly
+  modified `nnkOpenSymChoice` node but macros that want to support the
+  experimental feature should still handle `nnkOpenSym`, as the node kind would
+  simply not be generated as opposed to being removed.
+
+  Another experimental switch `genericsOpenSym` exists that enables this behavior
+  at instantiation time, meaning templates etc can enable it specifically when
+  they are being called. However this does not generate `nnkOpenSym` nodes
+  (unless the other switch is enabled) and so doesn't reflect the regular
+  behavior of the switch.
+
+  ```nim
+  const value = "captured"
+  template foo(x: int, body: untyped): untyped =
+    let value {.inject.} = "injected"
+    {.push experimental: "genericsOpenSym".}
+    body
+    {.pop.}
+
+  proc bar[T](): string =
+    foo(123):
+      return value
+  echo bar[int]() # "injected"
+
+  template barTempl(): string =
+    block:
+      var res: string
+      foo(123):
+        res = value
+      res
+  assert barTempl() == "injected"
+  ```
+
+
+
+
+
 ## Compiler changes
 
+- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.
+
+
+
+
+
 ## Tool changes
 
+- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package.
diff --git a/changelogs/changelog_X_XX_X.md b/changelogs/changelog_X_XX_X.md
index 524599b11..f8a09a535 100644
--- a/changelogs/changelog_X_XX_X.md
+++ b/changelogs/changelog_X_XX_X.md
@@ -1,4 +1,4 @@
-# v1.xx.x - yyyy-mm-dd
+# v2.xx.x - yyyy-mm-dd
 
 This is an example file.
 The changes should go to changelog.md!
diff --git a/compiler/ast.nim b/compiler/ast.nim
index e8fee6c0d..a342e1ea7 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -41,7 +41,7 @@ type
   TNodeKinds* = set[TNodeKind]
 
 type
-  TSymFlag* = enum    # 51 flags!
+  TSymFlag* = enum    # 63 flags!
     sfUsed,           # read access of sym (for warnings) or simply used
     sfExported,       # symbol is exported from module
     sfFromGeneric,    # symbol is instantiation of a generic; this is needed
@@ -93,7 +93,7 @@ type
     sfNamedParamCall, # symbol needs named parameter call syntax in target
                       # language; for interfacing with Objective C
     sfDiscardable,    # returned value may be discarded implicitly
-    sfOverridden,      # proc is overridden
+    sfOverridden,     # proc is overridden
     sfCallsite        # A flag for template symbols to tell the
                       # compiler it should use line information from
                       # the calling side of the macro, not from the
@@ -126,24 +126,25 @@ type
     sfByCopy          # param is marked as pass bycopy
     sfMember          # proc is a C++ member of a type
     sfCodegenDecl     # type, proc, global or proc param is marked as codegenDecl
+    sfWasGenSym       # symbol was 'gensym'ed
+    sfForceLift       # variable has to be lifted into closure environment
+
+    sfDirty           # template is not hygienic (old styled template) module,
+                      # compiled from a dirty-buffer
+    sfCustomPragma    # symbol is custom pragma template
+    sfBase,           # a base method
+    sfGoto            # var is used for 'goto' code generation
+    sfAnon,           # symbol name that was generated by the compiler
+                      # the compiler will avoid printing such names
+                      # in user messages.
+    sfAllUntyped      # macro or template is immediately expanded in a generic context
+    sfTemplateRedefinition # symbol is a redefinition of an earlier template
 
   TSymFlags* = set[TSymFlag]
 
 const
   sfNoInit* = sfMainModule       # don't generate code to init the variable
 
-  sfAllUntyped* = sfVolatile # macro or template is immediately expanded \
-    # in a generic context
-
-  sfDirty* = sfPure
-    # template is not hygienic (old styled template)
-    # module, compiled from a dirty-buffer
-
-  sfAnon* = sfDiscardable
-    # symbol name that was generated by the compiler
-    # the compiler will avoid printing such names
-    # in user messages.
-
   sfNoForward* = sfRegister
     # forward declarations are not required (per module)
   sfReorder* = sfForward
@@ -152,12 +153,8 @@ const
   sfCompileToCpp* = sfInfixCall       # compile the module as C++ code
   sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
   sfExperimental* = sfOverridden       # module uses the .experimental switch
-  sfGoto* = sfOverridden               # var is used for 'goto' code generation
   sfWrittenTo* = sfBorrow             # param is assigned to
                                       # currently unimplemented
-  sfBase* = sfDiscriminant
-  sfCustomPragma* = sfRegister        # symbol is custom pragma template
-  sfTemplateRedefinition* = sfExportc # symbol is a redefinition of an earlier template
   sfCppMember* = { sfVirtual, sfMember, sfConstructor } # proc is a C++ member, meaning it will be attached to the type definition
 
 const
@@ -217,7 +214,8 @@ type
     tyUncheckedArray
       # An array with boundaries [0,+∞]
 
-    tyProxy # used as errornous type (for idetools)
+    tyError # used as erroneous type (for idetools)
+      # as an erroneous node should match everything
 
     tyBuiltInTypeClass
       # Type such as the catch-all object, tuple, seq, etc
@@ -279,10 +277,6 @@ static:
 const
   tyPureObject* = tyTuple
   GcTypeKinds* = {tyRef, tySequence, tyString}
-  tyError* = tyProxy # as an errornous node should match everything
-  tyUnknown* = tyFromExpr
-
-  tyUnknownTypes* = {tyError, tyFromExpr}
 
   tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass,
                     tyUserTypeClass, tyUserTypeClassInst,
@@ -328,7 +322,9 @@ type
     nfFirstWrite # this node is a first write
     nfHasComment # node has a comment
     nfSkipFieldChecking # node skips field visable checking
-    nfOpenSym # node is a captured sym but can be overriden by local symbols
+    nfDisabledOpenSym # temporary: node should be nkOpenSym but cannot
+                      # because openSym experimental switch is disabled
+                      # gives warning instead
 
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 47)
@@ -449,6 +445,8 @@ const
   tfGcSafe* = tfThread
   tfObjHasKids* = tfEnumHasHoles
   tfReturnsNew* = tfInheritable
+  tfNonConstExpr* = tfExplicitCallConv
+    ## tyFromExpr where the expression shouldn't be evaluated as a static value
   skError* = skUnknown
 
 var
@@ -504,7 +502,7 @@ type
     mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
     mNewString, mNewStringOfCap, mParseBiggestFloat,
     mMove, mEnsureMove, mWasMoved, mDup, mDestroy, mTrace,
-    mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
+    mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField,
     mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
     mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
     mOrdinal, mIterableType,
@@ -654,7 +652,7 @@ type
     storage*: TStorageLoc
     flags*: TLocFlags         # location's flags
     lode*: PNode              # Node where the location came from; can be faked
-    r*: Rope                  # rope value of location (code generators)
+    snippet*: Rope            # C code snippet of location (code generators)
 
   # ---------------- end of backend information ------------------------------
 
@@ -883,7 +881,7 @@ const
                                       nfFromTemplate, nfDefaultRefsParam,
                                       nfExecuteOnReload, nfLastRead,
                                       nfFirstWrite, nfSkipFieldChecking,
-                                      nfOpenSym}
+                                      nfDisabledOpenSym}
   namePos* = 0
   patternPos* = 1    # empty except for term rewriting macros
   genericParamsPos* = 2
@@ -897,7 +895,7 @@ const
   nfAllFieldsSet* = nfBase2
 
   nkIdentKinds* = {nkIdent, nkSym, nkAccQuoted, nkOpenSymChoice,
-                   nkClosedSymChoice}
+                   nkClosedSymChoice, nkOpenSym}
 
   nkPragmaCallKinds* = {nkExprColonExpr, nkCall, nkCallStrLit}
   nkLiterals* = {nkCharLit..nkTripleStrLit}
@@ -925,6 +923,7 @@ proc getPIdent*(a: PNode): PIdent {.inline.} =
   of nkSym: a.sym.name
   of nkIdent: a.ident
   of nkOpenSymChoice, nkClosedSymChoice: a.sons[0].sym.name
+  of nkOpenSym: getPIdent(a.sons[0])
   else: nil
 
 const
@@ -1058,8 +1057,11 @@ proc getDeclPragma*(n: PNode): PNode =
 
 proc extractPragma*(s: PSym): PNode =
   ## gets the pragma node of routine/type/var/let/const symbol `s`
-  if s.kind in routineKinds:
-    result = s.ast[pragmasPos]
+  if s.kind in routineKinds: # bug #24167
+    if s.ast[pragmasPos] != nil and s.ast[pragmasPos].kind != nkEmpty:
+      result = s.ast[pragmasPos]
+    else:
+      result = nil
   elif s.kind in {skType, skVar, skLet, skConst}:
     if s.ast != nil and s.ast.len > 0:
       if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:
@@ -1285,6 +1287,9 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
   result.typ = sym.typ
   result.info = info
 
+proc newOpenSym*(n: PNode): PNode {.inline.} =
+  result = newTreeI(nkOpenSym, n.info, n)
+
 proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
   result = newNode(kind)
   result.intVal = intVal
@@ -1509,13 +1514,14 @@ proc newType*(kind: TTypeKind; idgen: IdGenerator; owner: PSym; son: sink PType
 
 proc setSons*(dest: PType; sons: sink seq[PType]) {.inline.} = dest.sons = sons
 proc setSon*(dest: PType; son: sink PType) {.inline.} = dest.sons = @[son]
+proc setSonsLen*(dest: PType; len: int) {.inline.} = setLen(dest.sons, len)
 
 proc mergeLoc(a: var TLoc, b: TLoc) =
   if a.k == low(typeof(a.k)): a.k = b.k
   if a.storage == low(typeof(a.storage)): a.storage = b.storage
   a.flags.incl b.flags
   if a.lode == nil: a.lode = b.lode
-  if a.r == "": a.r = b.r
+  if a.snippet == "": a.snippet = b.snippet
 
 proc newSons*(father: PNode, length: int) =
   setLen(father.sons, length)
diff --git a/compiler/astyaml.nim b/compiler/astyaml.nim
index c7e090cd3..b0fa2bfb2 100644
--- a/compiler/astyaml.nim
+++ b/compiler/astyaml.nim
@@ -75,7 +75,7 @@ proc symToYamlAux(res: var string; conf: ConfigRef; n: PSym; marker: var IntSet;
     res.addf("\n$1storage: $2", [istr, makeYamlString($n.loc.storage)])
     if card(n.loc.flags) > 0:
       res.addf("\n$1flags: $2", [istr, makeYamlString($n.loc.flags)])
-    res.addf("\n$1r: $2", [istr, n.loc.r])
+    res.addf("\n$1snippet: $2", [istr, n.loc.snippet])
     res.addf("\n$1lode: $2", [istr])
     res.treeToYamlAux(conf, n.loc.lode, marker, indent + 1, maxRecDepth - 1)
 
diff --git a/compiler/backendpragmas.nim b/compiler/backendpragmas.nim
deleted file mode 100644
index b18644810..000000000
--- a/compiler/backendpragmas.nim
+++ /dev/null
@@ -1,25 +0,0 @@
-import pragmas, options, ast, trees
-
-proc pushBackendOption(optionsStack: var seq[TOptions], options: var TOptions) =
-  optionsStack.add options
-
-proc popBackendOption(optionsStack: var seq[TOptions], options: var TOptions) =
-  options = optionsStack[^1]
-  optionsStack.setLen(optionsStack.len-1)
-
-proc processPushBackendOption*(optionsStack: var seq[TOptions], options: var TOptions,
-                           n: PNode, start: int) =
-  pushBackendOption(optionsStack, options)
-  for i in start..<n.len:
-    let it = n[i]
-    if it.kind in nkPragmaCallKinds and it.len == 2 and it[1].kind == nkIntLit:
-      let sw = whichPragma(it[0])
-      let opts = pragmaToOptions(sw)
-      if opts != {}:
-        if it[1].intVal != 0:
-          options.incl opts
-        else:
-          options.excl opts
-
-template processPopBackendOption*(optionsStack: var seq[TOptions], options: var TOptions) =
-  popBackendOption(optionsStack, options)
diff --git a/compiler/cbuilder.nim b/compiler/cbuilder.nim
new file mode 100644
index 000000000..bb1bdfe27
--- /dev/null
+++ b/compiler/cbuilder.nim
@@ -0,0 +1,174 @@
+type
+  Snippet = string
+  Builder = string
+
+template newBuilder(s: string): Builder =
+  s
+
+proc addField(obj: var Builder; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
+  obj.add('\t')
+  obj.add(typ)
+  obj.add(" ")
+  obj.add(name)
+  if isFlexArray:
+    obj.add("[SEQ_DECL_SIZE]")
+  if initializer.len != 0:
+    obj.add(initializer)
+  obj.add(";\n")
+
+proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") =
+  ## for fields based on an `skField` symbol
+  obj.add('\t')
+  if field.alignment > 0:
+    obj.add("NIM_ALIGN(")
+    obj.addInt(field.alignment)
+    obj.add(") ")
+  obj.add(typ)
+  if sfNoalias in field.flags:
+    obj.add(" NIM_NOALIAS")
+  obj.add(" ")
+  obj.add(name)
+  if isFlexArray:
+    obj.add("[SEQ_DECL_SIZE]")
+  if field.bitsize != 0:
+    obj.add(":")
+    obj.addInt(field.bitsize)
+  if initializer.len != 0:
+    obj.add(initializer)
+  obj.add(";\n")
+
+type
+  BaseClassKind = enum
+    bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
+  StructBuilderInfo = object
+    baseKind: BaseClassKind
+    preFieldsLen: int
+
+proc structOrUnion(t: PType): Snippet =
+  let t = t.skipTypes({tyAlias, tySink})
+  if tfUnion in t.flags: "union"
+  else: "struct"
+
+proc ptrType(t: Snippet): Snippet =
+  t & "*"
+
+proc startSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet): StructBuilderInfo =
+  result = StructBuilderInfo(baseKind: bcNone)
+  obj.add("struct ")
+  obj.add(name)
+  if baseType.len != 0:
+    if m.compileToCpp:
+      result.baseKind = bcCppInherit
+    else:
+      result.baseKind = bcSupField
+  if result.baseKind == bcCppInherit:
+    obj.add(" : public ")
+    obj.add(baseType)
+  obj.add(" ")
+  obj.add("{\n")
+  result.preFieldsLen = obj.len
+  if result.baseKind == bcSupField:
+    obj.addField(name = "Sup", typ = baseType)
+
+proc finishSimpleStruct(obj: var Builder; m: BModule; info: StructBuilderInfo) =
+  if info.baseKind == bcNone and info.preFieldsLen == obj.len:
+    # no fields were added, add dummy field
+    obj.addField(name = "dummy", typ = "char")
+  obj.add("};\n")
+
+template addSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet; body: typed) =
+  ## for independent structs, not directly based on a Nim type
+  let info = startSimpleStruct(obj, m, name, baseType)
+  body
+  finishSimpleStruct(obj, m, info)
+
+proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType: Snippet): StructBuilderInfo =
+  result = StructBuilderInfo(baseKind: bcNone)
+  if tfPacked in t.flags:
+    if hasAttribute in CC[m.config.cCompiler].props:
+      obj.add(structOrUnion(t))
+      obj.add(" __attribute__((__packed__))")
+    else:
+      obj.add("#pragma pack(push, 1)\n")
+      obj.add(structOrUnion(t))
+  else:
+    obj.add(structOrUnion(t))
+  obj.add(" ")
+  obj.add(name)
+  if t.kind == tyObject:
+    if t.baseClass == nil:
+      if lacksMTypeField(t):
+        result.baseKind = bcNone
+      elif optTinyRtti in m.config.globalOptions:
+        result.baseKind = bcNoneTinyRtti
+      else:
+        result.baseKind = bcNoneRtti
+    elif m.compileToCpp:
+      result.baseKind = bcCppInherit
+    else:
+      result.baseKind = bcSupField
+  elif baseType.len != 0:
+    if m.compileToCpp:
+      result.baseKind = bcCppInherit
+    else:
+      result.baseKind = bcSupField
+  if result.baseKind == bcCppInherit:
+    obj.add(" : public ")
+    obj.add(baseType)
+  obj.add(" ")
+  obj.add("{\n")
+  result.preFieldsLen = obj.len
+  case result.baseKind
+  of bcNone:
+    # rest of the options add a field or don't need it due to inheritance,
+    # we need to add the dummy field for uncheckedarray ahead of time
+    # so that it remains trailing
+    if t.itemId notin m.g.graph.memberProcsPerType and
+        t.n != nil and t.n.len == 1 and t.n[0].kind == nkSym and
+        t.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
+      # only consists of flexible array field, add *initial* dummy field
+      obj.addField(name = "dummy", typ = "char")
+  of bcCppInherit: discard
+  of bcNoneRtti:
+    obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimType")))
+  of bcNoneTinyRtti:
+    obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2")))
+  of bcSupField:
+    obj.addField(name = "Sup", typ = baseType)
+
+proc finishStruct(obj: var Builder; m: BModule; t: PType; info: StructBuilderInfo) =
+  if info.baseKind == bcNone and info.preFieldsLen == obj.len and
+      t.itemId notin m.g.graph.memberProcsPerType:
+    # no fields were added, add dummy field
+    obj.addField(name = "dummy", typ = "char")
+  obj.add("};\n")
+  if tfPacked in t.flags and hasAttribute notin CC[m.config.cCompiler].props:
+    obj.add("#pragma pack(pop)\n")
+
+template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: Snippet; body: typed) =
+  ## for structs built directly from a Nim type
+  let info = startStruct(obj, m, typ, name, baseType)
+  body
+  finishStruct(obj, m, typ, info)
+
+template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
+  ## adds a field with a `struct { ... }` type, building it according to `body`
+  obj.add('\t')
+  if tfPacked in parentTyp.flags:
+    if hasAttribute in CC[m.config.cCompiler].props:
+      obj.add("struct __attribute__((__packed__)) {\n")
+    else:
+      obj.add("#pragma pack(push, 1)\nstruct {")
+  else:
+    obj.add("struct {\n")
+  body
+  obj.add("} ")
+  obj.add(fieldName)
+  obj.add(";\n")
+  if tfPacked in parentTyp.flags and hasAttribute notin CC[m.config.cCompiler].props:
+    result.add("#pragma pack(pop)\n")
+
+template addAnonUnion(obj: var Builder; body: typed) =
+  obj.add "union{\n"
+  body
+  obj.add("};\n")
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 607f6d51e..ac607e3ad 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -76,6 +76,23 @@ proc isHarmlessStore(p: BProc; canRaise: bool; d: TLoc): bool =
   else:
     result = false
 
+proc cleanupTemp(p: BProc; returnType: PType, tmp: TLoc): bool =
+  if returnType.kind in {tyVar, tyLent}:
+    # we don't need to worry about var/lent return types
+    result = false
+  elif hasDestructor(returnType) and getAttachedOp(p.module.g.graph, returnType, attachedDestructor) != nil:
+    let dtor = getAttachedOp(p.module.g.graph, returnType, attachedDestructor)
+    var op = initLocExpr(p, newSymNode(dtor))
+    var callee = rdLoc(op)
+    let destroy = if dtor.typ.firstParamType.kind == tyVar:
+        callee & "(&" & rdLoc(tmp) & ")"
+      else:
+        callee & "(" & rdLoc(tmp) & ")"
+    raiseExitCleanup(p, destroy)
+    result = true
+  else:
+    result = false
+
 proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
                callee, params: Rope) =
   let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
@@ -115,7 +132,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
           # with them to prevent undefined behaviour and because the codegen
           # is free to emit expressions multiple times!
           d.k = locCall
-          d.r = pl
+          d.snippet = pl
           excl d.flags, lfSingleUse
         else:
           if d.k == locNone and p.splitDecls == 0:
@@ -123,35 +140,48 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
           else:
             if d.k == locNone: d = getTemp(p, typ.returnType)
             var list = initLoc(locCall, d.lode, OnUnknown)
-            list.r = pl
-            genAssignment(p, d, list, {}) # no need for deep copying
+            list.snippet = pl
+            genAssignment(p, d, list, {needAssignCall}) # no need for deep copying
             if canRaise: raiseExit(p)
 
       elif isHarmlessStore(p, canRaise, d):
-        if d.k == locNone: d = getTemp(p, typ.returnType)
+        var useTemp = false
+        if d.k == locNone:
+          useTemp = true
+          d = getTemp(p, typ.returnType)
         assert(d.t != nil)        # generate an assignment to d:
         var list = initLoc(locCall, d.lode, OnUnknown)
-        list.r = pl
-        genAssignment(p, d, list, flags) # no need for deep copying
-        if canRaise: raiseExit(p)
+        list.snippet = pl
+        genAssignment(p, d, list, flags+{needAssignCall}) # no need for deep copying
+        if canRaise:
+          if not (useTemp and cleanupTemp(p, typ.returnType, d)):
+            raiseExit(p)
       else:
         var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
         var list = initLoc(locCall, d.lode, OnUnknown)
-        list.r = pl
-        genAssignment(p, tmp, list, flags) # no need for deep copying
-        if canRaise: raiseExit(p)
+        list.snippet = pl
+        genAssignment(p, tmp, list, flags+{needAssignCall}) # no need for deep copying
+        if canRaise:
+          if not cleanupTemp(p, typ.returnType, tmp):
+            raiseExit(p)
         genAssignment(p, d, tmp, {})
   else:
     pl.add(");\n")
     line(p, cpsStmts, pl)
     if canRaise: raiseExit(p)
 
-proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
+proc genBoundsCheck(p: BProc; arr, a, b: TLoc; arrTyp: PType)
 
 proc reifiedOpenArray(n: PNode): bool {.inline.} =
   var x = n
-  while x.kind in {nkAddr, nkHiddenAddr, nkHiddenStdConv, nkHiddenDeref}:
-    x = x[0]
+  while true:
+    case x.kind
+    of {nkAddr, nkHiddenAddr, nkHiddenDeref}:
+      x = x[0]
+    of nkHiddenStdConv:
+      x = x[1]
+    else:
+      break
   if x.kind == nkSym and x.sym.kind == skParam:
     result = false
   else:
@@ -161,12 +191,15 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
   var a = initLocExpr(p, q[1])
   var b = initLocExpr(p, q[2])
   var c = initLocExpr(p, q[3])
+  # bug #23321: In the function mapType, ptrs (tyPtr, tyVar, tyLent, tyRef)
+  # are mapped into ctPtrToArray, the dereference of which is skipped
+  # in the `genDeref`. We need to skip these ptrs here
+  let ty = skipTypes(a.t, abstractVar+{tyPtr, tyRef})
   # but first produce the required index checks:
   if optBoundsCheck in p.options:
-    genBoundsCheck(p, a, b, c)
+    genBoundsCheck(p, a, b, c, ty)
   if prepareForMutation:
     linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
-  let ty = skipTypes(a.t, abstractVar+{tyPtr})
   let dest = getTypeDesc(p.module, destType)
   let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
   case ty.kind
@@ -241,7 +274,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
           optSeqDestructors in p.config.globalOptions:
         linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
       if ntyp.kind in {tyVar} and not compileToCpp(p.module):
-        var t = TLoc(r: "(*$1)" % [a.rdLoc])
+        var t = TLoc(snippet: "(*$1)" % [a.rdLoc])
         result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
                      [a.rdLoc, lenExpr(p, t), dataField(p),
                       dataFieldAccessor(p, "*" & a.rdLoc)]
@@ -253,7 +286,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
     of tyPtr, tyRef:
       case elementType(a.t).kind
       of tyString, tySequence:
-        var t = TLoc(r: "(*$1)" % [a.rdLoc])
+        var t = TLoc(snippet: "(*$1)" % [a.rdLoc])
         result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
                      [a.rdLoc, lenExpr(p, t), dataField(p),
                       dataFieldAccessor(p, "*" & a.rdLoc)]
@@ -298,18 +331,33 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
       addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result)
   elif p.module.compileToCpp and param.typ.kind in {tyVar} and
       n.kind == nkHiddenAddr:
-    a = initLocExprSingleUse(p, n[0])
+    # bug #23748: we need to introduce a temporary here. The expression type
+    # will be a reference in C++ and we cannot create a temporary reference
+    # variable. Thus, we create a temporary pointer variable instead.
+    let needsIndirect = mapType(p.config, n[0].typ, mapTypeChooser(n[0]) == skParam) != ctArray
+    if needsIndirect:
+      n.typ = n.typ.exactReplica
+      n.typ.flags.incl tfVarIsPtr
+    a = initLocExprSingleUse(p, n)
+    a = withTmpIfNeeded(p, a, needsTmp)
+    if needsIndirect: a.flags.incl lfIndirect
     # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
     # means '*T'. See posix.nim for lots of examples that do that in the wild.
     let callee = call[0]
     if callee.kind == nkSym and
         {sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and
-        {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
+        {lfHeader, lfNoDecl} * callee.sym.loc.flags != {} and
+        needsIndirect:
       addAddrLoc(p.config, a, result)
     else:
       addRdLoc(a, result)
   else:
     a = initLocExprSingleUse(p, n)
+    if param.typ.kind in {tyVar, tyPtr, tyRef, tySink}:
+      let typ = skipTypes(param.typ, abstractPtrs)
+      if not sameBackendTypePickyAliases(typ, n.typ.skipTypes(abstractPtrs)):
+        a.snippet = "(($1) ($2))" %
+          [getTypeDesc(p.module, param.typ), rdCharLoc(a)]
     addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
   #assert result != nil
 
@@ -354,7 +402,7 @@ proc getPotentialWrites(n: PNode; mutate: bool; result: var seq[PNode]) =
   of nkCallKinds:
     case n.getMagic:
     of mIncl, mExcl, mInc, mDec, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
-        mAddr, mNew, mNewFinalize, mWasMoved, mDestroy, mReset:
+        mAddr, mNew, mNewFinalize, mWasMoved, mDestroy:
       getPotentialWrites(n[1], true, result)
       for i in 2..<n.len:
         getPotentialWrites(n[i], mutate, result)
@@ -392,9 +440,11 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
         if not needTmp[i - 1]:
           needTmp[i - 1] = potentialAlias(n, potentialWrites)
       getPotentialWrites(ri[i], false, potentialWrites)
-    if ri[i].kind in {nkHiddenAddr, nkAddr}:
-      # Optimization: don't use a temp, if we would only take the address anyway
-      needTmp[i - 1] = false
+    when false:
+      # this optimization is wrong, see bug #23748
+      if ri[i].kind in {nkHiddenAddr, nkAddr}:
+        # Optimization: don't use a temp, if we would only take the address anyway
+        needTmp[i - 1] = false
 
   var oldLen = result.len
   for i in 1..<ri.len:
@@ -482,9 +532,9 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
       assert(d.t != nil)        # generate an assignment to d:
       var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
       if tfIterator in typ.flags:
-        list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
+        list.snippet = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
       else:
-        list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
+        list.snippet = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
       genAssignment(p, d, list, {}) # no need for deep copying
       if canRaise: raiseExit(p)
     else:
@@ -492,9 +542,9 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
       assert(d.t != nil)        # generate an assignment to d:
       var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
       if tfIterator in typ.flags:
-        list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
+        list.snippet = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
       else:
-        list.r = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
+        list.snippet = PatProc % [rdLoc(op), pl, pl.addComma, rawProc]
       genAssignment(p, tmp, list, {})
       if canRaise: raiseExit(p)
       genAssignment(p, d, tmp, {})
@@ -677,7 +727,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var typ = skipTypes(ri[0].typ, abstractInst)
   assert(typ.kind == tyProc)
   # don't call '$' here for efficiency:
-  let pat = $ri[0].sym.loc.r
+  let pat = $ri[0].sym.loc.snippet
   internalAssert p.config, pat.len > 0
   if pat.contains({'#', '(', '@', '\''}):
     var pl = newRopeAppender()
@@ -690,13 +740,13 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
         # with them to prevent undefined behaviour and because the codegen
         # is free to emit expressions multiple times!
         d.k = locCall
-        d.r = pl
+        d.snippet = pl
         excl d.flags, lfSingleUse
       else:
         if d.k == locNone: d = getTemp(p, typ.returnType)
         assert(d.t != nil)        # generate an assignment to d:
         var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
-        list.r = pl
+        list.snippet = pl
         genAssignment(p, d, list, {}) # no need for deep copying
     else:
       pl.add(";\n")
@@ -706,7 +756,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
     var argsCounter = 0
     if 1 < ri.len:
       genThisArg(p, ri, 1, typ, pl)
-    pl.add(op.r)
+    pl.add(op.snippet)
     var params = newRopeAppender()
     for i in 2..<ri.len:
       genOtherArg(p, ri, i, typ, params, argsCounter)
@@ -721,12 +771,12 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   assert(typ.kind == tyProc)
 
   # don't call '$' here for efficiency:
-  let pat = $ri[0].sym.loc.r
+  let pat = $ri[0].sym.loc.snippet
   internalAssert p.config, pat.len > 0
   var start = 3
   if ' ' in pat:
     start = 1
-    pl.add(op.r)
+    pl.add(op.snippet)
     if ri.len > 1:
       pl.add(": ")
       genArg(p, ri[1], typ.n[1].sym, ri, pl)
@@ -735,7 +785,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
     if ri.len > 1:
       genArg(p, ri[1], typ.n[1].sym, ri, pl)
       pl.add(" ")
-    pl.add(op.r)
+    pl.add(op.snippet)
     if ri.len > 2:
       pl.add(": ")
       genArg(p, ri[2], typ.n[2].sym, ri, pl)
@@ -770,7 +820,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
       if d.k == locNone: d = getTemp(p, typ.returnType)
       assert(d.t != nil)        # generate an assignment to d:
       var list: TLoc = initLoc(locCall, ri, OnUnknown)
-      list.r = pl
+      list.snippet = pl
       genAssignment(p, d, list, {}) # no need for deep copying
   else:
     pl.add("];\n")
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 042af01f1..545d43ae8 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -224,7 +224,7 @@ proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc =
   result = TLoc(k: locField,
     storage: a.storage,
     lode: lodeTyp t,
-    r: rdLoc(a) & "." & field
+    snippet: rdLoc(a) & "." & field
   )
 
 proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
@@ -254,9 +254,9 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
   case t.kind
   of nkSym:
     let field = t.sym
-    if field.loc.r == "": fillObjectFields(p.module, typ)
-    genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r),
-                     optAsgnLoc(src, field.typ, field.loc.r), newflags)
+    if field.loc.snippet == "": fillObjectFields(p.module, typ)
+    genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.snippet),
+                     optAsgnLoc(src, field.typ, field.loc.snippet), newflags)
   of nkRecList:
     for child in items(t): genOptAsgnObject(p, dest, src, newflags, child, typ)
   else: discard
@@ -343,7 +343,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   of tyString:
     if optSeqDestructors in p.config.globalOptions:
       genGenericAsgn(p, dest, src, flags)
-    elif (needToCopy notin flags and src.storage != OnStatic) or canMove(p, src.lode, dest):
+    elif ({needToCopy, needToCopySinkParam} * flags == {} and src.storage != OnStatic) or canMove(p, src.lode, dest):
       genRefAssign(p, dest, src)
     else:
       if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config):
@@ -379,7 +379,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     elif not isObjLackingTypeField(ty):
       genGenericAsgn(p, dest, src, flags)
     elif containsGarbageCollectedRef(ty):
-      if ty[0].isNil and asgnComplexity(ty.n) <= 4:
+      if ty[0].isNil and asgnComplexity(ty.n) <= 4 and
+            needAssignCall notin flags: # calls might contain side effects
         discard getTypeDesc(p.module, ty)
         internalAssert p.config, ty.n != nil
         genOptAsgnObject(p, dest, src, flags, ty.n, ty)
@@ -482,7 +483,7 @@ proc putDataIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope) =
   if d.k != locNone:
     var a: TLoc = initLoc(locData, n, OnStatic)
     # need to generate an assignment here
-    a.r = r
+    a.snippet = r
     if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
     else: genAssignment(p, d, a, {needToCopy})
   else:
@@ -490,13 +491,13 @@ proc putDataIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope) =
     # the flags field!
     d.k = locData
     d.lode = n
-    d.r = r
+    d.snippet = r
 
 proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) =
   if d.k != locNone:
     # need to generate an assignment here
     var a: TLoc = initLoc(locExpr, n, s)
-    a.r = r
+    a.snippet = r
     if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
     else: genAssignment(p, d, a, {needToCopy})
   else:
@@ -504,7 +505,7 @@ proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) =
     # the flags field!
     d.k = locExpr
     d.lode = n
-    d.r = r
+    d.snippet = r
 
 proc binaryStmt(p: BProc, e: PNode, d: var TLoc, op: string) =
   if d.k != locNone: internalError(p.config, e.info, "binaryStmt")
@@ -589,7 +590,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
   # skipping 'range' is correct here as we'll generate a proper range check
   # later via 'chckRange'
   let t = e.typ.skipTypes(abstractRange)
-  if optOverflowCheck notin p.options:
+  if optOverflowCheck notin p.options or (m in {mSucc, mPred} and t.kind in {tyUInt..tyUInt64}):
     let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
     putIntoDest(p, d, e, res)
   else:
@@ -808,10 +809,12 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
   # careful  'addr(myptrToArray)' needs to get the ampersand:
   if e[0].typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}:
     var a: TLoc = initLocExpr(p, e[0])
-    putIntoDest(p, d, e, "&" & a.r, a.storage)
+    putIntoDest(p, d, e, "&" & a.snippet, a.storage)
     #Message(e.info, warnUser, "HERE NEW &")
   elif mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam) == ctArray or isCppRef(p, e.typ):
     expr(p, e[0], d)
+    # bug #19497
+    d.lode = e
   else:
     var a: TLoc = initLocExpr(p, e[0])
     putIntoDest(p, d, e, addrLoc(p.config, a), a.storage)
@@ -877,10 +880,10 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
   else:
     var rtyp: PType = nil
     let field = lookupFieldAgain(p, ty, f, r, addr rtyp)
-    if field.loc.r == "" and rtyp != nil: fillObjectFields(p.module, rtyp)
-    if field.loc.r == "": internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty))
+    if field.loc.snippet == "" and rtyp != nil: fillObjectFields(p.module, rtyp)
+    if field.loc.snippet == "": internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty))
     r.add "."
-    r.add field.loc.r
+    r.add field.loc.snippet
     putIntoDest(p, d, e, r, a.storage)
   r.freeze
 
@@ -899,10 +902,10 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
     test = initLoc(locNone, it, OnStack)
     u = initLocExpr(p, it[1])
     v = initLoc(locExpr, disc, OnUnknown)
-    v.r = newRopeAppender()
-    v.r.add obj
-    v.r.add(".")
-    v.r.add(disc.sym.loc.r)
+    v.snippet = newRopeAppender()
+    v.snippet.add obj
+    v.snippet.add(".")
+    v.snippet.add(disc.sym.loc.snippet)
     genInExprAux(p, it, u, v, test)
     var msg = ""
     if optDeclaredLocs in p.config.globalOptions:
@@ -960,12 +963,12 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
     var r = rdLoc(a)
     let f = e[0][1].sym
     let field = lookupFieldAgain(p, ty, f, r)
-    if field.loc.r == "": fillObjectFields(p.module, ty)
-    if field.loc.r == "":
+    if field.loc.snippet == "": fillObjectFields(p.module, ty)
+    if field.loc.snippet == "":
       internalError(p.config, e.info, "genCheckedRecordField") # generate the checks:
     genFieldCheck(p, e, r, field)
     r.add(".")
-    r.add field.loc.r
+    r.add field.loc.snippet
     putIntoDest(p, d, e[0], r, a.storage)
     r.freeze
   else:
@@ -1019,8 +1022,8 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   putIntoDest(p, d, n,
               ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
 
-proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
-  let ty = skipTypes(arr.t, abstractVarRange)
+proc genBoundsCheck(p: BProc; arr, a, b: TLoc; arrTyp: PType) =
+  let ty = arrTyp
   case ty.kind
   of tyOpenArray, tyVarargs:
     if reifiedOpenArray(arr.lode):
@@ -1100,7 +1103,7 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
 
   if d.k == locNone: d.storage = OnHeap
   if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
-    a.r = ropecg(p.module, "(*$1)", [a.r])
+    a.snippet = ropecg(p.module, "(*$1)", [a.snippet])
 
   if lfPrepareForMutation in d.flags and ty.kind == tyString and
       optSeqDestructors in p.config.globalOptions:
@@ -1166,9 +1169,9 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     var tmpB = initLocExprSingleUse(p, e[2])
     tmpB.k = locExpr
     if m == mOr:
-      tmpB.r = "((" & rdLoc(tmpA) & ")||(" & rdLoc(tmpB) & "))"
+      tmpB.snippet = "((" & rdLoc(tmpA) & ")||(" & rdLoc(tmpB) & "))"
     else:
-      tmpB.r = "((" & rdLoc(tmpA) & ")&&(" & rdLoc(tmpB) & "))"
+      tmpB.snippet = "((" & rdLoc(tmpA) & ")&&(" & rdLoc(tmpB) & "))"
     if d.k == locNone:
       d = tmpB
     else:
@@ -1271,7 +1274,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
         lens.add(lenExpr(p, a))
         lens.add(" + ")
       appends.add(ropecg(p.module, "#appendString($1, $2);$n", [strLoc(p, tmp), rdLoc(a)]))
-  linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, L])
+  linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.snippet, lens, L])
   p.s(cpsStmts).add appends
   if d.k == locNone:
     d = tmp
@@ -1317,7 +1320,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
             [byRefLoc(p, dest), lens, L])
   else:
     call = initLoc(locCall, e, OnHeap)
-    call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, L])
+    call.snippet = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, L])
     genAssignment(p, dest, call, {})
     gcUsage(p.config, e)
   p.s(cpsStmts).add appends
@@ -1332,12 +1335,12 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   var call = initLoc(locCall, e, OnHeap)
   if not p.module.compileToCpp:
     const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)"
-    call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
+    call.snippet = ropecg(p.module, seqAppendPattern, [rdLoc(a),
       getTypeDesc(p.module, e[1].typ),
       genTypeInfoV1(p.module, seqType, e.info)])
   else:
     const seqAppendPattern = "($2) #incrSeqV3($1, $3)"
-    call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
+    call.snippet = ropecg(p.module, seqAppendPattern, [rdLoc(a),
       getTypeDesc(p.module, e[1].typ),
       genTypeInfoV1(p.module, seqType, e.info)])
   # emit the write barrier if required, but we can always move here, so
@@ -1347,19 +1350,11 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   #  echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
   var dest = initLoc(locExpr, e[2], OnHeap)
   var tmpL = getIntTemp(p)
-  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)])
+  lineCg(p, cpsStmts, "$1 = $2->$3++;$n", [tmpL.snippet, rdLoc(a), lenField(p)])
+  dest.snippet = ropecg(p.module, "$1$3[$2]", [rdLoc(a), tmpL.snippet, dataField(p)])
   genAssignment(p, dest, b, {needToCopy})
   gcUsage(p.config, e)
 
-proc genReset(p: BProc, n: PNode) =
-  var a: TLoc = initLocExpr(p, n[1])
-  specializeReset(p, a)
-  when false:
-    linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
-            [addrLoc(p.config, a),
-            genTypeInfoV1(p.module, skipTypes(a.t, {tyVar}), n.info)])
-
 proc genDefault(p: BProc; n: PNode; d: var TLoc) =
   if d.k == locNone: d = getTemp(p, n.typ, needsInit=true)
   else: resetLoc(p, d)
@@ -1376,10 +1371,10 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
 
   if optTinyRtti in p.config.globalOptions:
     if needsInit:
-      b.r = ropecg(p.module, "($1) #nimNewObj($2, NIM_ALIGNOF($3))",
+      b.snippet = ropecg(p.module, "($1) #nimNewObj($2, NIM_ALIGNOF($3))",
           [getTypeDesc(p.module, typ), sizeExpr, getTypeDesc(p.module, bt)])
     else:
-      b.r = ropecg(p.module, "($1) #nimNewObjUninit($2, NIM_ALIGNOF($3))",
+      b.snippet = ropecg(p.module, "($1) #nimNewObjUninit($2, NIM_ALIGNOF($3))",
           [getTypeDesc(p.module, typ), sizeExpr, getTypeDesc(p.module, bt)])
     genAssignment(p, a, b, {})
   else:
@@ -1404,15 +1399,15 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
       if p.config.selectedGC == gcGo:
         # newObjRC1() would clash with unsureAsgnRef() - which is used by gcGo to
         # implement the write barrier
-        b.r = ropecg(p.module, "($1) #newObj($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr])
+        b.snippet = ropecg(p.module, "($1) #newObj($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr])
         linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n",
                 [addrLoc(p.config, a), b.rdLoc])
       else:
         # use newObjRC1 as an optimization
-        b.r = ropecg(p.module, "($1) #newObjRC1($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr])
+        b.snippet = ropecg(p.module, "($1) #newObjRC1($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr])
         linefmt(p, cpsStmts, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
     else:
-      b.r = ropecg(p.module, "($1) #newObj($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr])
+      b.snippet = ropecg(p.module, "($1) #newObj($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr])
       genAssignment(p, a, b, {})
   # set the object type:
   genObjectInit(p, cpsStmts, bt, a, constructRefObj)
@@ -1438,18 +1433,18 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
     if not lenIsZero:
       if p.config.selectedGC == gcGo:
         # we need the write barrier
-        call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype),
+        call.snippet = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype),
               genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
         linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", [addrLoc(p.config, dest), call.rdLoc])
       else:
-        call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", [getTypeDesc(p.module, seqtype),
+        call.snippet = ropecg(p.module, "($1) #newSeqRC1($2, $3)", [getTypeDesc(p.module, seqtype),
               genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
         linefmt(p, cpsStmts, "$1 = $2;$n", [dest.rdLoc, call.rdLoc])
   else:
     if lenIsZero:
-      call.r = rope"NIM_NIL"
+      call.snippet = rope"NIM_NIL"
     else:
-      call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype),
+      call.snippet = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype),
               genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
     genAssignment(p, dest, call, {})
 
@@ -1492,9 +1487,13 @@ proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
   if id == p.module.labels:
     # expression not found in the cache:
     inc(p.module.labels)
-    p.module.s[cfsData].addf("static NIM_CONST $1 $2 = ", [getTypeDesc(p.module, t), d.r])
-    genBracedInit(p, n, isConst = true, t, p.module.s[cfsData])
-    p.module.s[cfsData].addf(";$n", [])
+    var data = "static NIM_CONST $1 $2 = " % [getTypeDesc(p.module, t), d.snippet]
+    # bug #23627; when generating const object fields, it's likely that
+    # we need to generate type infos for the object, which may be an object with
+    # custom hooks. We need to generate potential consts in the hooks first.
+    genBracedInit(p, n, isConst = true, t, data)
+    data.addf(";$n", [])
+    p.module.s[cfsData].add data
 
 proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
   if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
@@ -1505,15 +1504,14 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
 
 
 proc genFieldObjConstr(p: BProc; ty: PType; useTemp, isRef: bool; nField, val, check: PNode; d: var TLoc; r: Rope; info: TLineInfo) =
-  var tmp2: TLoc = default(TLoc)
-  tmp2.r = r
-  let field = lookupFieldAgain(p, ty, nField.sym, tmp2.r)
-  if field.loc.r == "": fillObjectFields(p.module, ty)
-  if field.loc.r == "": internalError(p.config, info, "genFieldObjConstr")
+  var tmp2 = TLoc(snippet: r)
+  let field = lookupFieldAgain(p, ty, nField.sym, tmp2.snippet)
+  if field.loc.snippet == "": fillObjectFields(p.module, ty)
+  if field.loc.snippet == "": internalError(p.config, info, "genFieldObjConstr")
   if check != nil and optFieldCheck in p.options:
     genFieldCheck(p, check, r, field)
-  tmp2.r.add(".")
-  tmp2.r.add(field.loc.r)
+  tmp2.snippet.add(".")
+  tmp2.snippet.add(field.loc.snippet)
   if useTemp:
     tmp2.k = locTemp
     tmp2.storage = if isRef: OnHeap else: OnStack
@@ -1521,7 +1519,12 @@ proc genFieldObjConstr(p: BProc; ty: PType; useTemp, isRef: bool; nField, val, c
     tmp2.k = d.k
     tmp2.storage = if isRef: OnHeap else: d.storage
   tmp2.lode = val
-  expr(p, val, tmp2)
+  if nField.typ.skipTypes(abstractVar).kind in {tyOpenArray, tyVarargs}:
+    var tmp3 = getTemp(p, val.typ)
+    expr(p, val, tmp3)
+    genOpenArrayConv(p, tmp2, tmp3, {})
+  else:
+    expr(p, val, tmp2)
 
 proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
   # inheritance in C++ does not allow struct initialization so
@@ -1607,7 +1610,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
     arr = initLoc(locExpr, n[i], OnHeap)
     var lit = newRopeAppender()
     intLiteral(i, lit)
-    arr.r = ropecg(p.module, "$1$3[$2]", [rdLoc(dest[]), lit, dataField(p)])
+    arr.snippet = ropecg(p.module, "$1$3[$2]", [rdLoc(dest[]), lit, dataField(p)])
     arr.storage = OnHeap            # we know that sequences are on the heap
     expr(p, n[i], arr)
   gcUsage(p.config, n)
@@ -1643,19 +1646,19 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
       elem = initLoc(locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
       var lit = newRopeAppender()
       intLiteral(i, lit)
-      elem.r = ropecg(p.module, "$1$3[$2]", [rdLoc(d), lit, dataField(p)])
+      elem.snippet = ropecg(p.module, "$1$3[$2]", [rdLoc(d), lit, dataField(p)])
       elem.storage = OnHeap # we know that sequences are on the heap
       arr = initLoc(locExpr, lodeTyp elemType(skipTypes(n[1].typ, abstractInst)), a.storage)
-      arr.r = ropecg(p.module, "$1[$2]", [rdLoc(a), lit])
+      arr.snippet = ropecg(p.module, "$1[$2]", [rdLoc(a), lit])
       genAssignment(p, elem, arr, {needToCopy})
   else:
     var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
-    linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",  [i.r, L])
+    linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",  [i.snippet, L])
     elem = initLoc(locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
-    elem.r = ropecg(p.module, "$1$3[$2]", [rdLoc(d), rdLoc(i), dataField(p)])
+    elem.snippet = ropecg(p.module, "$1$3[$2]", [rdLoc(d), rdLoc(i), dataField(p)])
     elem.storage = OnHeap # we know that sequences are on the heap
     arr = initLoc(locExpr, lodeTyp elemType(skipTypes(n[1].typ, abstractInst)), a.storage)
-    arr.r = ropecg(p.module, "$1[$2]", [rdLoc(a), rdLoc(i)])
+    arr.snippet = ropecg(p.module, "$1[$2]", [rdLoc(a), rdLoc(i)])
     genAssignment(p, elem, arr, {needToCopy})
     lineF(p, cpsStmts, "}$n", [])
 
@@ -1671,7 +1674,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
   b = initLoc(locExpr, a.lode, OnHeap)
   ti = genTypeInfo(p.config, p.module, refType, e.info)
   p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
-  b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
+  b.snippet = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
       getTypeDesc(p.module, refType),
       ti, getTypeDesc(p.module, skipTypes(refType.elementType, abstractRange))])
   genAssignment(p, a, b, {})  # set the object type:
@@ -1836,7 +1839,7 @@ proc genAccessTypeField(p: BProc; e: PNode; d: var TLoc) =
 
 template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
   var a: TLoc = initLocExpr(p, n[1])
-  a.r = ropecg(p.module, frmt, [rdLoc(a)])
+  a.snippet = ropecg(p.module, frmt, [rdLoc(a)])
   a.flags.excl lfIndirect # this flag should not be propagated here (not just for HCR)
   if d.k == locNone: d = getTemp(p, n.typ)
   genAssignment(p, d, a, {})
@@ -1855,7 +1858,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       var b = initLocExpr(p, a[2])
       var c = initLocExpr(p, a[3])
       if optBoundsCheck in p.options:
-        genBoundsCheck(p, m, b, c)
+        genBoundsCheck(p, m, b, c, skipTypes(m.t, abstractVarRange))
       if op == mHigh:
         putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1))", [rdLoc(b), rdLoc(c)]))
       else:
@@ -1890,8 +1893,8 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     var a = initLocExpr(p, e[1])
     var x = lenExpr(p, a)
     if op == mHigh: x = "($1-1)" % [x]
-    lineCg(p, cpsStmts, "$1 = $2;$n", [tmp.r, x])
-    putIntoDest(p, d, e, tmp.r)
+    lineCg(p, cpsStmts, "$1 = $2;$n", [tmp.snippet, x])
+    putIntoDest(p, d, e, tmp.snippet)
   of tyArray:
     # YYY: length(sideeffect) is optimized away incorrectly?
     if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(p.config, typ)))
@@ -1913,13 +1916,13 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
   var call = initLoc(locCall, e, OnHeap)
   if not p.module.compileToCpp:
     const setLenPattern = "($3) #setLengthSeqV2(($1)?&($1)->Sup:NIM_NIL, $4, $2)"
-    call.r = ropecg(p.module, setLenPattern, [
+    call.snippet = ropecg(p.module, setLenPattern, [
       rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
       genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
 
   else:
     const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2)"
-    call.r = ropecg(p.module, setLenPattern, [
+    call.snippet = ropecg(p.module, setLenPattern, [
       rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
       genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
 
@@ -1935,7 +1938,7 @@ proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
     var b = initLocExpr(p, e[2])
 
     var call = initLoc(locCall, e, OnHeap)
-    call.r = ropecg(p.module, "#setLengthStr($1, $2)", [
+    call.snippet = ropecg(p.module, "#setLengthStr($1, $2)", [
         rdLoc(a), rdLoc(b)])
     genAssignment(p, a, call, {})
     gcUsage(p.config, e)
@@ -2012,23 +2015,23 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
     a = initLocExpr(p, ea)
     b = initLoc(locExpr, e, OnUnknown)
     if e[1].len > 0:
-      b.r = rope("(")
+      b.snippet = rope("(")
       for i in 0..<e[1].len:
         let it = e[1][i]
         if it.kind == nkRange:
           x = initLocExpr(p, it[0])
           y = initLocExpr(p, it[1])
-          b.r.addf("$1 >= $2 && $1 <= $3",
+          b.snippet.addf("$1 >= $2 && $1 <= $3",
                [rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)])
         else:
           x = initLocExpr(p, it)
-          b.r.addf("$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
-        if i < e[1].len - 1: b.r.add(" || ")
-      b.r.add(")")
+          b.snippet.addf("$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
+        if i < e[1].len - 1: b.snippet.add(" || ")
+      b.snippet.add(")")
     else:
       # handle the case of an empty set
-      b.r = rope("0")
-    putIntoDest(p, d, e, b.r)
+      b.snippet = rope("0")
+    putIntoDest(p, d, e, b.snippet)
   else:
     assert(e[1].typ != nil)
     assert(e[2].typ != nil)
@@ -2166,7 +2169,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
     inc(p.labels)
     var lbl = p.labels.rope
     var tmp: TLoc = default(TLoc)
-    tmp.r = "LOC$1.source" % [lbl]
+    tmp.snippet = "LOC$1.source" % [lbl]
     let destsize = getSize(p.config, destt)
     let srcsize = getSize(p.config, srct)
 
@@ -2231,12 +2234,16 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
       raiseInstr(p, p.s(cpsStmts))
       linefmt p, cpsStmts, "}$n", []
 
-  putIntoDest(p, d, n, "(($1) ($2))" %
+  if sameBackendTypeIgnoreRange(dest, n[0].typ):
+    # don't cast so an address can be taken for `var` conversions
+    putIntoDest(p, d, n, "($1)" % [rdCharLoc(a)], a.storage)
+  else:
+    putIntoDest(p, d, n, "(($1) ($2))" %
       [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
 
 proc genConv(p: BProc, e: PNode, d: var TLoc) =
   let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink})
-  if sameBackendType(destType, e[1].typ):
+  if sameBackendTypeIgnoreRange(destType, e[1].typ):
     expr(p, e[1], d)
   else:
     genSomeCast(p, e, d)
@@ -2345,8 +2352,13 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
           else:
             linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), byRefLoc(p, a)])
     else:
-      let flags = if not canMove(p, n[1], d): {needToCopy} else: {}
-      genAssignment(p, d, a, flags)
+      if n[1].kind == nkSym and isSinkParam(n[1].sym):
+        var tmp = getTemp(p, n[1].typ.skipTypes({tySink}))
+        genAssignment(p, tmp, a, {needToCopySinkParam})
+        genAssignment(p, d, tmp, {})
+        resetLoc(p, tmp)
+      else:
+        genAssignment(p, d, a, {})
       resetLoc(p, a)
 
 proc genDestroy(p: BProc; n: PNode) =
@@ -2454,7 +2466,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       var call = initLoc(locCall, e, OnHeap)
       var dest = initLocExpr(p, e[1])
       var b = initLocExpr(p, e[2])
-      call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)])
+      call.snippet = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)])
       genAssignment(p, dest, call, {})
   of mAppendStrStr: genStrAppend(p, e, d)
   of mAppendSeqElem:
@@ -2518,7 +2530,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     let member =
       if t.kind == tyTuple:
         "Field" & rope(dotExpr[1].sym.position)
-      else: dotExpr[1].sym.loc.r
+      else: dotExpr[1].sym.loc.snippet
     putIntoDest(p,d,e, "((NI)offsetof($1, $2))" % [tname, member])
   of mChr: genSomeCast(p, e, d)
   of mOrd: genOrd(p, e, d)
@@ -2541,8 +2553,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     # - not sure, and it wouldn't work if the symbol behind the magic isn't
     #   somehow forward-declared from some other usage, but it is *possible*
     if lfNoDecl notin opr.loc.flags:
-      let prc = magicsys.getCompilerProc(p.module.g.graph, $opr.loc.r)
-      assert prc != nil, $opr.loc.r
+      let prc = magicsys.getCompilerProc(p.module.g.graph, $opr.loc.snippet)
+      assert prc != nil, $opr.loc.snippet
       # HACK:
       # Explicitly add this proc as declared here so the cgsym call doesn't
       # add a forward declaration - without this we could end up with the same
@@ -2555,14 +2567,13 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       let wasDeclared = containsOrIncl(p.module.declaredProtos, prc.id)
       # Make the function behind the magic get actually generated - this will
       # not lead to a forward declaration! The genCall will lead to one.
-      cgsym(p.module, $opr.loc.r)
+      cgsym(p.module, $opr.loc.snippet)
       # make sure we have pointer-initialising code for hot code reloading
       if not wasDeclared and p.hcrOn:
         p.module.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
              [mangleDynLibProc(prc), getTypeDesc(p.module, prc.loc.t), getModuleDllPath(p.module, prc)])
     genCall(p, e, d)
   of mDefault, mZeroDefault: genDefault(p, e, d)
-  of mReset: genReset(p, e)
   of mEcho: genEcho(p, e[1].skipConv)
   of mArrToSeq: genArrToSeq(p, e, d)
   of mNLen..mNError, mSlurp..mQuoteAst:
@@ -2685,7 +2696,7 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
       var it = n[i]
       if it.kind == nkExprColonExpr: it = it[1]
       rec = initLoc(locExpr, it, dest[].storage)
-      rec.r = "$1.Field$2" % [rdLoc(dest[]), rope(i)]
+      rec.snippet = "$1.Field$2" % [rdLoc(dest[]), rope(i)]
       rec.flags.incl(lfEnforceDeref)
       expr(p, it, rec)
 
@@ -2735,12 +2746,12 @@ proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
       arr = initLoc(locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), d.storage)
       var lit = newRopeAppender()
       intLiteral(i, lit)
-      arr.r = "$1[$2]" % [rdLoc(d), lit]
+      arr.snippet = "$1[$2]" % [rdLoc(d), lit]
       expr(p, n[i], arr)
 
 proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) =
   requestConstImpl(p, sym)
-  assert((sym.loc.r != "") and (sym.loc.t != nil))
+  assert((sym.loc.snippet != "") and (sym.loc.t != nil))
   putLocIntoDest(p, d, sym.loc)
 
 template genStmtListExprImpl(exprOrStmt) {.dirty.} =
@@ -2872,24 +2883,24 @@ proc genConstSetup(p: BProc; sym: PSym): bool =
   result = lfNoDecl notin sym.loc.flags
 
 proc genConstHeader(m, q: BModule; p: BProc, sym: PSym) =
-  if sym.loc.r == "":
+  if sym.loc.snippet == "":
     if not genConstSetup(p, sym): return
-  assert(sym.loc.r != "", $sym.name.s & $sym.itemId)
+  assert(sym.loc.snippet != "", $sym.name.s & $sym.itemId)
   if m.hcrOn:
-    m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, dkVar), sym.loc.r]);
+    m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, dkVar), sym.loc.snippet]);
     m.initProc.procSec(cpsLocals).addf(
-      "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
+      "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.snippet,
       getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(q, sym)])
   else:
     let headerDecl = "extern NIM_CONST $1 $2;$n" %
-        [getTypeDesc(m, sym.loc.t, dkVar), sym.loc.r]
+        [getTypeDesc(m, sym.loc.t, dkVar), sym.loc.snippet]
     m.s[cfsData].add(headerDecl)
     if sfExportc in sym.flags and p.module.g.generatedHeader != nil:
       p.module.g.generatedHeader.s[cfsData].add(headerDecl)
 
 proc genConstDefinition(q: BModule; p: BProc; sym: PSym) =
   # add a suffix for hcr - will later init the global pointer with this data
-  let actualConstName = if q.hcrOn: sym.loc.r & "_const" else: sym.loc.r
+  let actualConstName = if q.hcrOn: sym.loc.snippet & "_const" else: sym.loc.snippet
   var data = newRopeAppender()
   data.addf("N_LIB_PRIVATE NIM_CONST $1 $2 = ",
            [getTypeDesc(q, sym.typ), actualConstName])
@@ -2898,16 +2909,16 @@ proc genConstDefinition(q: BModule; p: BProc; sym: PSym) =
   q.s[cfsData].add data
   if q.hcrOn:
     # generate the global pointer with the real name
-    q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, dkVar), sym.loc.r])
+    q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, dkVar), sym.loc.snippet])
     # register it (but ignore the boolean result of hcrRegisterGlobal)
     q.initProc.procSec(cpsLocals).addf(
       "\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n",
-      [getModuleDllPath(q, sym), sym.loc.r, rdLoc(sym.loc)])
+      [getModuleDllPath(q, sym), sym.loc.snippet, rdLoc(sym.loc)])
     # always copy over the contents of the actual constant with the _const
     # suffix ==> this means that the constant is reloadable & updatable!
     q.initProc.procSec(cpsLocals).add(ropecg(q,
       "\t#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n",
-      [sym.loc.r, actualConstName, rdLoc(sym.loc)]))
+      [sym.loc.snippet, actualConstName, rdLoc(sym.loc)]))
 
 proc genConstStmt(p: BProc, n: PNode) =
   # This code is only used in the new DCE implementation.
@@ -2947,7 +2958,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
         genProcPrototype(p.module, sym)
       else:
         genProc(p.module, sym)
-      if sym.loc.r == "" or sym.loc.lode == nil:
+      if sym.loc.snippet == "" or sym.loc.lode == nil:
         internalError(p.config, n.info, "expr: proc not init " & sym.name.s)
       putLocIntoDest(p, d, sym.loc)
     of skConst:
@@ -2957,7 +2968,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
         putIntoDest(p, d, n, lit, OnStatic)
       elif useAliveDataFromDce in p.module.flags:
         genConstHeader(p.module, p.module, p, sym)
-        assert((sym.loc.r != "") and (sym.loc.t != nil))
+        assert((sym.loc.snippet != "") and (sym.loc.t != nil))
         putLocIntoDest(p, d, sym.loc)
       else:
         genComplexConst(p, sym, d)
@@ -2972,14 +2983,14 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
         if sfCompileTime in sym.flags:
           genSingleVar(p, sym, n, astdef(sym))
 
-      if sym.loc.r == "" or sym.loc.t == nil:
+      if sym.loc.snippet == "" or sym.loc.t == nil:
         #echo "FAILED FOR PRCO ", p.prc.name.s
         #echo renderTree(p.prc.ast, {renderIds})
         internalError p.config, n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
       if sfThread in sym.flags:
         accessThreadLocalVar(p, sym)
         if emulatedThreadVars(p.config):
-          putIntoDest(p, d, sym.loc.lode, "NimTV_->" & sym.loc.r)
+          putIntoDest(p, d, sym.loc.lode, "NimTV_->" & sym.loc.snippet)
         else:
           putLocIntoDest(p, d, sym.loc)
       else:
@@ -2987,17 +2998,17 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     of skTemp:
       when false:
         # this is more harmful than helpful.
-        if sym.loc.r == "":
+        if sym.loc.snippet == "":
           # we now support undeclared 'skTemp' variables for easier
           # transformations in other parts of the compiler:
           assignLocalVar(p, n)
-      if sym.loc.r == "" or sym.loc.t == nil:
+      if sym.loc.snippet == "" or sym.loc.t == nil:
         #echo "FAILED FOR PRCO ", p.prc.name.s
         #echo renderTree(p.prc.ast, {renderIds})
         internalError(p.config, n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id)
       putLocIntoDest(p, d, sym.loc)
     of skParam:
-      if sym.loc.r == "" or sym.loc.t == nil:
+      if sym.loc.snippet == "" or sym.loc.t == nil:
         # echo "FAILED FOR PRCO ", p.prc.name.s
         # debug p.prc.typ.n
         # echo renderTree(p.prc.ast, {renderIds})
@@ -3087,7 +3098,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkLambdaKinds:
     var sym = n[namePos].sym
     genProc(p.module, sym)
-    if sym.loc.r == "" or sym.loc.lode == nil:
+    if sym.loc.snippet == "" or sym.loc.lode == nil:
       internalError(p.config, n.info, "expr: proc not init " & sym.name.s)
     putLocIntoDest(p, d, sym.loc)
   of nkClosure: genClosure(p, n, d)
@@ -3118,7 +3129,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     if ex.kind != nkEmpty:
       genLineDir(p, n)
       var a: TLoc = initLocExprSingleUse(p, ex)
-      line(p, cpsStmts, "(void)(" & a.r & ");\L")
+      line(p, cpsStmts, "(void)(" & a.snippet & ");\L")
   of nkAsmStmt: genAsmStmt(p, n)
   of nkTryStmt, nkHiddenTryStmt:
     case p.config.exc
@@ -3240,7 +3251,8 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
       getNullValueAux(p, t, it, constOrNil, result, count, isConst, info)
   of nkRecCase:
     getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info)
-    if count > 0: result.add ", "
+    var res = ""
+    if count > 0: res.add ", "
     var branch = Zero
     if constOrNil != nil:
       ## find kind value, default is zero if not specified
@@ -3254,18 +3266,21 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
           break
 
     let selectedBranch = caseObjDefaultBranch(obj, branch)
-    result.add "{"
+    res.add "{"
     var countB = 0
     let b = lastSon(obj[selectedBranch])
     # designated initilization is the only way to init non first element of unions
     # branches are allowed to have no members (b.len == 0), in this case they don't need initializer
     if b.kind == nkRecList and not isEmptyCaseObjectBranch(b):
-      result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
-      getNullValueAux(p, t,  b, constOrNil, result, countB, isConst, info)
-      result.add "}"
+      res.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
+      getNullValueAux(p, t,  b, constOrNil, res, countB, isConst, info)
+      res.add "}"
     elif b.kind == nkSym:
-      result.add "." & mangleRecFieldName(p.module, b.sym) & " = "
-      getNullValueAux(p, t,  b, constOrNil, result, countB, isConst, info)
+      res.add "." & mangleRecFieldName(p.module, b.sym) & " = "
+      getNullValueAux(p, t,  b, constOrNil, res, countB, isConst, info)
+    else:
+      return
+    result.add res
     result.add "}"
 
   of nkSym:
diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim
index 4af690e35..6caeb8084 100644
--- a/compiler/ccgreset.nim
+++ b/compiler/ccgreset.nim
@@ -24,10 +24,10 @@ proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
   of nkRecCase:
     if (n[0].kind != nkSym): internalError(p.config, n.info, "specializeResetN")
     let disc = n[0].sym
-    if disc.loc.r == "": fillObjectFields(p.module, typ)
+    if disc.loc.snippet == "": fillObjectFields(p.module, typ)
     if disc.loc.t == nil:
       internalError(p.config, n.info, "specializeResetN()")
-    lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
+    lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.snippet])
     for i in 1..<n.len:
       let branch = n[i]
       assert branch.kind in {nkOfBranch, nkElse}
@@ -38,14 +38,14 @@ proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
       specializeResetN(p, accessor, lastSon(branch), typ)
       lineF(p, cpsStmts, "break;$n", [])
     lineF(p, cpsStmts, "} $n", [])
-    specializeResetT(p, "$1.$2" % [accessor, disc.loc.r], disc.loc.t)
+    specializeResetT(p, "$1.$2" % [accessor, disc.loc.snippet], disc.loc.t)
   of nkSym:
     let field = n.sym
     if field.typ.kind == tyVoid: return
-    if field.loc.r == "": fillObjectFields(p.module, typ)
+    if field.loc.snippet == "": fillObjectFields(p.module, typ)
     if field.loc.t == nil:
       internalError(p.config, n.info, "specializeResetN()")
-    specializeResetT(p, "$1.$2" % [accessor, field.loc.r], field.loc.t)
+    specializeResetT(p, "$1.$2" % [accessor, field.loc.snippet], field.loc.t)
   else: internalError(p.config, n.info, "specializeResetN()")
 
 proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
@@ -59,8 +59,8 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
     let arraySize = lengthOrd(p.config, typ.indexType)
     var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
     linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
-            [i.r, arraySize])
-    specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.r]), typ.elementType)
+            [i.snippet, arraySize])
+    specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
     lineF(p, cpsStmts, "}$n", [])
   of tyObject:
     var x = typ.baseClass
@@ -96,7 +96,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
       raiseAssert "unexpected set type kind"
   of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
       tyGenericParam, tyOrdinal, tyOpenArray, tyForward, tyVarargs,
-      tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
+      tyUncheckedArray, tyError, tyBuiltInTypeClass, tyUserTypeClass,
       tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
       tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable:
     discard
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 345639d94..883108f2c 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -110,10 +110,10 @@ proc genVarTuple(p: BProc, n: PNode) =
       initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
     var field = initLoc(locExpr, vn, tup.storage)
     if t.kind == tyTuple:
-      field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
+      field.snippet = "$1.Field$2" % [rdLoc(tup), rope(i)]
     else:
       if t.n[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
-      field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n[i].sym)]
+      field.snippet = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n[i].sym)]
     putLocIntoDest(p, v.loc, field)
     if forHcr or isGlobalInBlock:
       hcrGlobals.add((loc: v.loc, tp: "NULL"))
@@ -128,7 +128,7 @@ proc genVarTuple(p: BProc, n: PNode) =
     lineCg(p, cpsLocals, "NIM_BOOL $1 = NIM_FALSE;$n", [hcrCond])
     for curr in hcrGlobals:
       lineCg(p, cpsLocals, "$1 |= hcrRegisterGlobal($4, \"$2\", sizeof($3), $5, (void**)&$2);$N",
-              [hcrCond, curr.loc.r, rdLoc(curr.loc), getModuleDllPath(p.module, n[0].sym), curr.tp])
+              [hcrCond, curr.loc.snippet, rdLoc(curr.loc), getModuleDllPath(p.module, n[0].sym), curr.tp])
 
 
 proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
@@ -267,11 +267,11 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
 
   if n[0].kind == nkClosure:
     a = initLocExpr(p, n[0][1])
-    d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
+    d.snippet = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
   else:
     a = initLocExpr(p, n[0])
     # the environment is guaranteed to contain the 'state' field at offset 1:
-    d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
+    d.snippet = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
 
 proc genGotoVar(p: BProc; value: PNode) =
   if value.kind notin {nkCharLit..nkUInt64Lit}:
@@ -289,7 +289,7 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
     #echo "New code produced for ", v.name.s, " ", p.config $ value.info
     genBracedInit(p, value, isConst = false, v.typ, result)
 
-proc genCppParamsForCtor(p: BProc; call: PNode): string =
+proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): string =
   result = ""
   var argsCounter = 0
   let typ = skipTypes(call[0].typ, abstractInst)
@@ -298,12 +298,23 @@ proc genCppParamsForCtor(p: BProc; call: PNode): string =
     #if it's a type we can just generate here another initializer as we are in an initializer context
     if call[i].kind == nkCall and call[i][0].kind == nkSym and call[i][0].sym.kind == skType:
       if argsCounter > 0: result.add ","
-      result.add genCppInitializer(p.module, p, call[i][0].sym.typ)
+      result.add genCppInitializer(p.module, p, call[i][0].sym.typ, didGenTemp)
     else:
+      #We need to test for temp in globals, see: #23657
+      let param =
+        if typ[i].kind in {tyVar} and call[i].kind == nkHiddenAddr:
+          call[i][0]
+        else:
+          call[i]
+      if param.kind != nkBracketExpr or param.typ.kind in
+        {tyRef, tyPtr, tyUncheckedArray, tyArray, tyOpenArray,
+          tyVarargs, tySequence, tyString, tyCstring, tyTuple}:
+        let tempLoc = initLocExprSingleUse(p, param)
+        didGenTemp = didGenTemp or tempLoc.k == locTemp
       genOtherArg(p, call, i, typ, result, argsCounter)
 
-proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope) =
-  let params = genCppParamsForCtor(p, call)
+proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope, didGenTemp: var bool) =
+  let params = genCppParamsForCtor(p, call, didGenTemp)
   if params.len == 0:
     decl = runtimeFormat("$#;\n", [decl])
   else:
@@ -330,7 +341,14 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
       # v.owner.kind != skModule:
       targetProc = p.module.preInitProc
     if isCppCtorCall and not containsHiddenPointer(v.typ):
-      callGlobalVarCppCtor(targetProc, v, vn, value)
+      var didGenTemp = false
+      callGlobalVarCppCtor(targetProc, v, vn, value, didGenTemp)
+      if didGenTemp:
+        message(p.config, vn.info, warnGlobalVarConstructorTemporary, vn.sym.name.s)
+        #We fail to call the constructor in the global scope so we do the call inside the main proc
+        assignGlobalVar(targetProc, vn, valueAsRope)
+        var loc = initLocExprSingleUse(targetProc, value)
+        genAssignment(targetProc, v.loc, loc, {})
     else:
       assignGlobalVar(targetProc, vn, valueAsRope)
 
@@ -365,7 +383,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
       var decl = localVarDecl(p, vn)
       var tmp: TLoc
       if isCppCtorCall:
-        genCppVarForCtor(p, value, decl)
+        var didGenTemp = false
+        genCppVarForCtor(p, value, decl, didGenTemp)
         line(p, cpsStmts, decl)
       else:
         tmp = initLocExprSingleUse(p, value)
@@ -386,7 +405,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
     # put it in the locals section - mainly because of loops which
     # use the var in a call to resetLoc() in the statements section
     lineCg(targetProc, cpsLocals, "hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1);$n",
-           [v.loc.r, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc])
+           [v.loc.snippet, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc])
     # nothing special left to do later on - let's avoid closing and reopening blocks
     forHcr = false
 
@@ -395,7 +414,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
   # be able to re-run it but without the top level code - just the init of globals
   if forHcr:
     lineCg(targetProc, cpsStmts, "if (hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1))$N",
-           [v.loc.r, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc])
+           [v.loc.snippet, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc])
     startBlock(targetProc)
   if value.kind != nkEmpty and valueAsRope.len == 0:
     genLineDir(targetProc, vn)
@@ -736,6 +755,18 @@ proc raiseExit(p: BProc) =
       lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n",
         [p.nestedTryStmts[^1].label])
 
+proc raiseExitCleanup(p: BProc, destroy: string) =
+  assert p.config.exc == excGoto
+  if nimErrorFlagDisabled notin p.flags:
+    p.flags.incl nimErrorFlagAccessed
+    if p.nestedTryStmts.len == 0:
+      p.flags.incl beforeRetNeeded
+      # easy case, simply goto 'ret':
+      lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$1; goto BeforeRet_;}$n", [destroy])
+    else:
+      lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$2; goto LA$1_;}$n",
+        [p.nestedTryStmts[^1].label, destroy])
+
 proc finallyActions(p: BProc) =
   if p.config.exc != excGoto and p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept:
     # if the current try stmt have a finally block,
@@ -765,10 +796,14 @@ proc genRaiseStmt(p: BProc, t: PNode) =
     var e = rdLoc(a)
     discard getTypeDesc(p.module, t[0].typ)
     var typ = skipTypes(t[0].typ, abstractPtrs)
-    # XXX For reasons that currently escape me, this is only required by the new
-    # C++ based exception handling:
-    if p.config.exc == excCpp:
+    case p.config.exc
+    of excCpp:
       blockLeaveActions(p, howManyTrys = 0, howManyExcepts = p.inExceptBlockLen)
+    of excGoto:
+      blockLeaveActions(p, howManyTrys = 0,
+        howManyExcepts = (if p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept: 1 else: 0))
+    else:
+      discard
     genLineDir(p, t)
     if isImportedException(typ, p.config):
       lineF(p, cpsStmts, "throw $1;$n", [e])
@@ -1510,7 +1545,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
       else:
         discard getTypeDesc(p.module, skipTypes(sym.typ, abstractPtrs))
         fillBackendName(p.module, sym)
-        res.add($sym.loc.r)
+        res.add($sym.loc.snippet)
     of nkTypeOfExpr:
       res.add($getTypeDesc(p.module, it.typ))
     else:
@@ -1547,14 +1582,14 @@ proc genAsmStmt(p: BProc, t: PNode) =
       if whichPragma(i) == wAsmSyntax:
         asmSyntax = i[1].strVal
 
-  if asmSyntax != "" and 
+  if asmSyntax != "" and
      not (
       asmSyntax == "gcc" and hasGnuAsm in CC[p.config.cCompiler].props or
       asmSyntax == "vcc" and hasGnuAsm notin CC[p.config.cCompiler].props):
     localError(
-      p.config, t.info, 
+      p.config, t.info,
       "Your compiler does not support the specified inline assembler")
-  
+
   genAsmOrEmitStmt(p, t, isAsmStmt=true, s)
   # see bug #2362, "top level asm statements" seem to be a mis-feature
   # but even if we don't do this, the example in #2362 cannot possibly
@@ -1592,9 +1627,9 @@ proc genPragma(p: BProc, n: PNode) =
     case whichPragma(it)
     of wEmit: genEmit(p, it)
     of wPush:
-      processPushBackendOption(p.optionsStack, p.options, n, i+1)
+      processPushBackendOption(p.config, p.optionsStack, p.options, n, i+1)
     of wPop:
-      processPopBackendOption(p.optionsStack, p.options)
+      processPopBackendOption(p.config, p.optionsStack, p.options)
     else: discard
 
 
diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim
index abf830b57..1f551f022 100644
--- a/compiler/ccgthreadvars.nim
+++ b/compiler/ccgthreadvars.nim
@@ -30,7 +30,7 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
     # allocator for it :-(
     if not containsOrIncl(m.g.nimtvDeclared, s.id):
       m.g.nimtvDeps.add(s.loc.t)
-      m.g.nimtv.addf("$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
+      m.g.nimtv.addf("$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.snippet])
   else:
     if isExtern: m.s[cfsVars].add("extern ")
     elif lfExportLib in s.loc.flags: m.s[cfsVars].add("N_LIB_EXPORT_VAR ")
@@ -41,7 +41,7 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
         m.s[cfsVars].add("NIM_THREAD_LOCAL ")
       else: m.s[cfsVars].add("NIM_THREADVAR ")
     m.s[cfsVars].add(getTypeDesc(m, s.loc.t))
-    m.s[cfsVars].addf(" $1;$n", [s.loc.r])
+    m.s[cfsVars].addf(" $1;$n", [s.loc.snippet])
 
 proc generateThreadLocalStorage(m: BModule) =
   if m.g.nimtv != "" and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index 3fd269bc6..ed4c79d9a 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -34,10 +34,10 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
     if (n[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
     var p = c.p
     let disc = n[0].sym
-    if disc.loc.r == "": fillObjectFields(c.p.module, typ)
+    if disc.loc.snippet == "": fillObjectFields(c.p.module, typ)
     if disc.loc.t == nil:
       internalError(c.p.config, n.info, "genTraverseProc()")
-    lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
+    lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.snippet])
     for i in 1..<n.len:
       let branch = n[i]
       assert branch.kind in {nkOfBranch, nkElse}
@@ -51,10 +51,10 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
   of nkSym:
     let field = n.sym
     if field.typ.kind == tyVoid: return
-    if field.loc.r == "": fillObjectFields(c.p.module, typ)
+    if field.loc.snippet == "": fillObjectFields(c.p.module, typ)
     if field.loc.t == nil:
       internalError(c.p.config, n.info, "genTraverseProc()")
-    genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
+    genTraverseProc(c, "$1.$2" % [accessor, field.loc.snippet], field.loc.t)
   else: internalError(c.p.config, n.info, "genTraverseProc()")
 
 proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
@@ -78,9 +78,9 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
     var oldCode = p.s(cpsStmts)
     freeze oldCode
     linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
-            [i.r, arraySize])
+            [i.snippet, arraySize])
     let oldLen = p.s(cpsStmts).len
-    genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.r]), typ.elementType)
+    genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
     if p.s(cpsStmts).len == oldLen:
       # do not emit dummy long loops for faster debug builds:
       p.s(cpsStmts) = oldCode
@@ -120,12 +120,12 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
   var i = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
   var oldCode = p.s(cpsStmts)
   freeze oldCode
-  var a = TLoc(r: accessor)
+  var a = TLoc(snippet: accessor)
 
   lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
-      [i.r, lenExpr(c.p, a)])
+      [i.snippet, lenExpr(c.p, a)])
   let oldLen = p.s(cpsStmts).len
-  genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ.elementType)
+  genTraverseProc(c, "$1$3[$2]" % [accessor, i.snippet, dataField(c.p)], typ.elementType)
   if p.s(cpsStmts).len == oldLen:
     # do not emit dummy long loops for faster debug builds:
     p.s(cpsStmts) = oldCode
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 1366caab3..2c2556336 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -55,24 +55,24 @@ proc mangleField(m: BModule; name: PIdent): string =
   if isKeyword(name):
     result.add "_0"
 
-proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string = 
+proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
   result = "_Z"  # Common prefix in Itanium ABI
   result.add encodeSym(m, s, makeUnique)
   if s.typ.len > 1: #we dont care about the return param
-    for i in 1..<s.typ.len: 
+    for i in 1..<s.typ.len:
       if s.typ[i].isNil: continue
       result.add encodeType(m, s.typ[i])
-  
+
   if result in m.g.mangledPrcs:
     result = mangleProc(m, s, true)
   else:
     m.g.mangledPrcs.incl(result)
 
 proc fillBackendName(m: BModule; s: PSym) =
-  if s.loc.r == "":
+  if s.loc.snippet == "":
     var result: Rope
     if not m.compileToCpp and s.kind in routineKinds and optCDebug in m.g.config.globalOptions and
-      m.g.config.symbolFiles == disabledSf: 
+      m.g.config.symbolFiles == disabledSf:
       result = mangleProc(m, s, false).rope
     else:
       result = s.name.s.mangle.rope
@@ -80,11 +80,11 @@ proc fillBackendName(m: BModule; s: PSym) =
     if m.hcrOn:
       result.add '_'
       result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
-    s.loc.r = result
+    s.loc.snippet = result
     writeMangledName(m.ndi, s, m.config)
 
 proc fillParamName(m: BModule; s: PSym) =
-  if s.loc.r == "":
+  if s.loc.snippet == "":
     var res = s.name.s.mangle
     res.add mangleParamExt(s)
     #res.add idOrSig(s, res, m.sigConflicts, m.config)
@@ -104,13 +104,13 @@ proc fillParamName(m: BModule; s: PSym) =
     # and a function called in main or proxy uses `socket` as a parameter name.
     # That would lead to either needing to reload `proxy` or to overwrite the
     # executable file for the main module, which is running (or both!) -> error.
-    s.loc.r = res.rope
+    s.loc.snippet = res.rope
     writeMangledName(m.ndi, s, m.config)
 
 proc fillLocalName(p: BProc; s: PSym) =
   assert s.kind in skLocalVars+{skTemp}
   #assert sfGlobal notin s.flags
-  if s.loc.r == "":
+  if s.loc.snippet == "":
     var key = s.name.s.mangle
     let counter = p.sigConflicts.getOrDefault(key)
     var result = key.rope
@@ -120,7 +120,7 @@ proc fillLocalName(p: BProc; s: PSym) =
     elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key):
       result.add "_" & rope(counter+1)
     p.sigConflicts.inc(key)
-    s.loc.r = result
+    s.loc.snippet = result
     if s.kind != skTemp: writeMangledName(p.module.ndi, s, p.config)
 
 proc scopeMangledParam(p: BProc; param: PSym) =
@@ -147,23 +147,23 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
   var t = typ
   while true:
     if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}:
-      return t.sym.loc.r
+      return t.sym.loc.snippet
 
     if t.kind in irrelevantForBackend:
       t = t.skipModifier
     else:
       break
   let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.elementType else: typ
-  if typ.loc.r == "":
-    typ.typeName(typ.loc.r)
-    typ.loc.r.add $sig
+  if typ.loc.snippet == "":
+    typ.typeName(typ.loc.snippet)
+    typ.loc.snippet.add $sig
   else:
     when defined(debugSigHashes):
       # check consistency:
       var tn = newRopeAppender()
       typ.typeName(tn)
-      assert($typ.loc.r == $(tn & $sig))
-  result = typ.loc.r
+      assert($typ.loc.snippet == $(tn & $sig))
+  result = typ.loc.snippet
   if result == "": internalError(m.config, "getTypeName: " & $typ.kind)
 
 proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind =
@@ -189,7 +189,7 @@ proc mapType(conf: ConfigRef; typ: PType; isParam: bool): TCTypeKind =
   of tyObject, tyTuple: result = ctStruct
   of tyUserTypeClasses:
     doAssert typ.isResolvedUserTypeClass
-    return mapType(conf, typ.skipModifier, isParam)
+    result = mapType(conf, typ.skipModifier, isParam)
   of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
      tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned:
     result = mapType(conf, skipModifier(typ), isParam)
@@ -277,9 +277,12 @@ proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
       if rettype.isImportedCppType or t.isImportedCppType or
           (typ.callConv == ccCDecl and conf.selectedGC in {gcArc, gcAtomicArc, gcOrc}):
         # prevents nrvo for cdecl procs; # bug #23401
-        return false
-      result = containsGarbageCollectedRef(t) or
-          (t.kind == tyObject and not isObjLackingTypeField(t))
+        result = false
+      else:
+        result = containsGarbageCollectedRef(t) or
+            (t.kind == tyObject and not isObjLackingTypeField(t)) or
+            (getSize(conf, rettype) == szUnknownSize and (t.sym == nil or sfImportc notin t.sym.flags))
+
     else: result = false
 
 const
@@ -287,7 +290,7 @@ const
     "N_STDCALL", "N_CDECL", "N_SAFECALL",
     "N_SYSCALL", # this is probably not correct for all platforms,
                  # but one can #define it to what one wants
-    "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV", 
+    "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_THISCALL", "N_CLOSURE", "N_NOCONV",
     "N_NOCONV" #ccMember is N_NOCONV
     ]
 
@@ -318,7 +321,7 @@ proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) =
 proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope =
   if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
     useHeader(m, t.sym)
-    result = t.sym.loc.r
+    result = t.sym.loc.snippet
   else:
     result = rope(literal)
 
@@ -373,13 +376,6 @@ proc getTypePre(m: BModule; typ: PType; sig: SigHash): Rope =
     result = getSimpleTypeDesc(m, typ)
     if result == "": result = cacheGetType(m.typeCache, sig)
 
-proc structOrUnion(t: PType): Rope =
-  let cachedUnion = rope("union")
-  let cachedStruct = rope("struct")
-  let t = t.skipTypes({tyAlias, tySink})
-  if tfUnion in t.flags: cachedUnion
-  else: cachedStruct
-
 proc addForwardStructFormat(m: BModule; structOrUnion: Rope, typename: Rope) =
   if m.compileToCpp:
     m.s[cfsForwardTypes].addf "$1 $2;$n", [structOrUnion, typename]
@@ -478,8 +474,8 @@ macro unrollChars(x: static openArray[char], name, body: untyped) =
       copy body
     )))
 
-proc multiFormat*(frmt: var string, chars : static openArray[char], args: openArray[seq[string]]) =
-  var res : string
+proc multiFormat*(frmt: var string, chars: static openArray[char], args: openArray[seq[string]]) =
+  var res: string
   unrollChars(chars, c):
     res = ""
     let arg = args[find(chars, c)]
@@ -521,7 +517,8 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
                    weakDep=false;) =
   let t = prc.typ
   let isCtor = sfConstructor in prc.flags
-  if isCtor or (name[0] == '~' and sfMember in prc.flags): #destructors cant have void
+  if isCtor or (name[0] == '~' and sfMember in prc.flags):
+    # destructors can't have void
     rettype = ""
   elif t.returnType == nil or isInvalidReturnType(m.config, t):
     rettype = "void"
@@ -537,10 +534,10 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
     fillLoc(this.loc, locParam, t.n[1],
             this.paramStorageLoc)
     if this.typ.kind == tyPtr:
-      this.loc.r = "this"
+      this.loc.snippet = "this"
     else:
-      this.loc.r = "(*this)"
-    names.add this.loc.r
+      this.loc.snippet = "(*this)"
+    names.add this.loc.snippet
     types.add getTypeDescWeak(m, this.typ, check, dkParam)
 
   let firstParam = if isCtor: 1 else: 2
@@ -553,7 +550,7 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
         descKind = dkRefGenericParam
       else:
         descKind = dkRefParam
-    var typ, name : string
+    var typ, name: string
     fillParamName(m, param)
     fillLoc(param.loc, locParam, t.n[i],
             param.paramStorageLoc)
@@ -568,7 +565,7 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
     if sfNoalias in param.flags:
       typ.add("NIM_NOALIAS ")
 
-    name = param.loc.r
+    name = param.loc.snippet
     types.add typ
     names.add name
     if sfCodegenDecl notin param.flags:
@@ -628,9 +625,9 @@ proc genProcParams(m: BModule; t: PType, rettype, params: var Rope,
       typ.add("NIM_NOALIAS ")
     if sfCodegenDecl notin param.flags:
       params.add(typ)
-      params.add(param.loc.r)
+      params.add(param.loc.snippet)
     else:
-      params.add runtimeFormat(param.cgDeclFrmt, [typ, param.loc.r])
+      params.add runtimeFormat(param.cgDeclFrmt, [typ, param.loc.snippet])
     # declare the len field for open arrays:
     var arr = param.typ.skipTypes({tyGenericInst})
     if arr.kind in {tyVar, tyLent, tySink}: arr = arr.elementType
@@ -639,7 +636,7 @@ proc genProcParams(m: BModule; t: PType, rettype, params: var Rope,
       # this fixes the 'sort' bug:
       if param.typ.kind in {tyVar, tyLent}: param.loc.storage = OnUnknown
       # need to pass hidden parameter:
-      params.addf(", NI $1Len_$2", [param.loc.r, j.rope])
+      params.addf(", NI $1Len_$2", [param.loc.snippet, j.rope])
       inc(j)
       arr = arr[0].skipTypes({tySink})
   if t.returnType != nil and isInvalidReturnType(m.config, t):
@@ -667,7 +664,7 @@ proc genProcParams(m: BModule; t: PType, rettype, params: var Rope,
 
 proc mangleRecFieldName(m: BModule; field: PSym): Rope =
   if {sfImportc, sfExportc} * field.flags != {}:
-    result = field.loc.r
+    result = field.loc.snippet
   else:
     result = rope(mangleField(m, field.name))
   if result == "": internalError(m.config, field.info, "mangleRecFieldName")
@@ -679,9 +676,9 @@ proc hasCppCtor(m: BModule; typ: PType): bool =
       if sfConstructor in prc.flags:
         return true
 
-proc genCppParamsForCtor(p: BProc; call: PNode): string
+proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): string
 
-proc genCppInitializer(m: BModule, prc: BProc; typ: PType): string =
+proc genCppInitializer(m: BModule, prc: BProc; typ: PType; didGenTemp: var bool): string =
   #To avoid creating a BProc per test when called inside a struct nil BProc is allowed
   result = "{}"
   if typ.itemId in m.g.graph.initializersPerType:
@@ -690,13 +687,13 @@ proc genCppInitializer(m: BModule, prc: BProc; typ: PType): string =
       var p = prc
       if p == nil:
         p = BProc(module: m)
-      result = "{" & genCppParamsForCtor(p, call) & "}"
+      result = "{" & genCppParamsForCtor(p, call, didGenTemp) & "}"
       if prc == nil:
         assert p.blocks.len == 0, "BProc belongs to a struct doesnt have blocks"
 
 proc genRecordFieldsAux(m: BModule; n: PNode,
                         rectype: PType,
-                        check: var IntSet; result: var Rope; unionPrefix = "") =
+                        check: var IntSet; result: var Builder; unionPrefix = "") =
   case n.kind
   of nkRecList:
     for i in 0..<n.len:
@@ -713,63 +710,51 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
         let k = lastSon(n[i])
         if k.kind != nkSym:
           let structName = "_" & mangleRecFieldName(m, n[0].sym) & "_" & $i
-          var a = newRopeAppender()
+          var a = newBuilder("")
           genRecordFieldsAux(m, k, rectype, check, a, unionPrefix & $structName & ".")
-          if a != "":
-            if tfPacked notin rectype.flags:
-              unionBody.add("struct {")
-            else:
-              if hasAttribute in CC[m.config.cCompiler].props:
-                unionBody.add("struct __attribute__((__packed__)){")
-              else:
-                unionBody.addf("#pragma pack(push, 1)$nstruct{", [])
-            unionBody.add(a)
-            unionBody.addf("} $1;$n", [structName])
-            if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props:
-              unionBody.addf("#pragma pack(pop)$n", [])
+          if a.len != 0:
+            unionBody.addFieldWithStructType(m, rectype, structName):
+              unionBody.add(a)
         else:
           genRecordFieldsAux(m, k, rectype, check, unionBody, unionPrefix)
       else: internalError(m.config, "genRecordFieldsAux(record case branch)")
-    if unionBody != "":
-      result.addf("union{\n$1};$n", [unionBody])
+    if unionBody.len != 0:
+      result.addAnonUnion:
+        result.add(unionBody)
   of nkSym:
     let field = n.sym
     if field.typ.kind == tyVoid: return
     #assert(field.ast == nil)
     let sname = mangleRecFieldName(m, field)
     fillLoc(field.loc, locField, n, unionPrefix & sname, OnUnknown)
-    if field.alignment > 0:
-      result.addf "NIM_ALIGN($1) ", [rope(field.alignment)]
     # for importcpp'ed objects, we only need to set field.loc, but don't
     # have to recurse via 'getTypeDescAux'. And not doing so prevents problems
     # with heavily templatized C++ code:
     if not isImportedCppType(rectype):
-      let noAlias = if sfNoalias in field.flags: " NIM_NOALIAS" else: ""
-
       let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
+      var typ: Rope = ""
+      var isFlexArray = false
+      var initializer = ""
       if fieldType.kind == tyUncheckedArray:
-        result.addf("\t$1 $2[SEQ_DECL_SIZE];$n",
-            [getTypeDescAux(m, fieldType.elemType, check, dkField), sname])
+        typ = getTypeDescAux(m, fieldType.elemType, check, dkField)
+        isFlexArray = true
       elif fieldType.kind == tySequence:
         # we need to use a weak dependency here for trecursive_table.
-        result.addf("\t$1$3 $2;$n", [getTypeDescWeak(m, field.loc.t, check, dkField), sname, noAlias])
-      elif field.bitsize != 0:
-        result.addf("\t$1$4 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, rope($field.bitsize), noAlias])
+        typ = getTypeDescWeak(m, field.loc.t, check, dkField)
       else:
+        typ = getTypeDescAux(m, field.loc.t, check, dkField)
         # don't use fieldType here because we need the
         # tyGenericInst for C++ template support
         let noInit = sfNoInit in field.flags or (field.typ.sym != nil and sfNoInit in field.typ.sym.flags)
         if not noInit and (fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ)):
-          var initializer = genCppInitializer(m, nil, fieldType)
-          result.addf("\t$1$3 $2$4;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias, initializer])
-        else:
-          result.addf("\t$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
+          var didGenTemp = false
+          initializer = genCppInitializer(m, nil, fieldType, didGenTemp)
+      result.addField(field, sname, typ, isFlexArray, initializer)
   else: internalError(m.config, n.info, "genRecordFieldsAux()")
 
 proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl:bool = false)
 
-proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope =
-  result = newRopeAppender()
+proc addRecordFields(result: var Builder; m: BModule; typ: PType, check: var IntSet) =
   genRecordFieldsAux(m, typ.n, typ, check, result)
   if typ.itemId in m.g.graph.memberProcsPerType:
     let procs = m.g.graph.memberProcsPerType[typ.itemId]
@@ -791,88 +776,34 @@ proc fillObjectFields*(m: BModule; typ: PType) =
   # sometimes generic objects are not consistently merged. We patch over
   # this fact here.
   var check = initIntSet()
-  discard getRecordFields(m, typ, check)
+  var ignored = newBuilder("")
+  addRecordFields(ignored, m, typ, check)
 
 proc mangleDynLibProc(sym: PSym): Rope
 
-proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope,
-                   check: var IntSet, hasField:var bool): Rope =
-  result = ""
-  if typ.kind == tyObject:
-    if typ.baseClass == nil:
-      if lacksMTypeField(typ):
-        appcg(m, result, " {$n", [])
-      else:
-        if optTinyRtti in m.config.globalOptions:
-          appcg(m, result, " {$n#TNimTypeV2* m_type;$n", [])
-        else:
-          appcg(m, result, " {$n#TNimType* m_type;$n", [])
-        hasField = true
-    elif m.compileToCpp:
-      appcg(m, result, " : public $1 {$n", [baseType])
-      if typ.isException and m.config.exc == excCpp:
-        when false:
-          appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
-          if typ.sym.magic == mException:
-            # Add cleanup destructor to Exception base class
-            appcg(m, result, "~$1();$n", [name])
-            # define it out of the class body and into the procs section so we don't have to
-            # artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR)
-            appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name])
-      hasField = true
-    else:
-      appcg(m, result, " {$n  $1 Sup;$n", [baseType])
-      hasField = true
-  else:
-    result.addf(" {$n", [name])
-
 proc getRecordDesc(m: BModule; typ: PType, name: Rope,
                    check: var IntSet): Rope =
   # declare the record:
-  var hasField = false
-  var structOrUnion: string
-  if tfPacked in typ.flags:
-      if hasAttribute in CC[m.config.cCompiler].props:
-        structOrUnion = structOrUnion(typ) & " __attribute__((__packed__))"
-      else:
-        structOrUnion = "#pragma pack(push, 1)\L" & structOrUnion(typ)
-  else:
-    structOrUnion = structOrUnion(typ)
   var baseType: string = ""
   if typ.baseClass != nil:
     baseType = getTypeDescAux(m, typ.baseClass.skipTypes(skipPtrs), check, dkField)
   if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
-    result = structOrUnion & " " & name
-    result.add(getRecordDescAux(m, typ, name, baseType, check, hasField))
-    let desc = getRecordFields(m, typ, check)
-    if not hasField and typ.itemId notin m.g.graph.memberProcsPerType:
-      if desc == "":
-        result.add("\tchar dummy;\n")
-      elif typ.n.len == 1 and typ.n[0].kind == nkSym:
-        let field = typ.n[0].sym
-        let fieldType = field.typ.skipTypes(abstractInst)
-        if fieldType.kind == tyUncheckedArray:
-          result.add("\tchar dummy;\n")
-      result.add(desc)
-    else:
-      result.add(desc)
-    result.add("};\L")
+    result = newBuilder("")
+    result.addStruct(m, typ, name, baseType):
+      result.addRecordFields(m, typ, check)
   else:
-    let desc = getRecordFields(m, typ, check)
+    var desc = newBuilder("")
+    desc.addRecordFields(m, typ, check)
     result = runtimeFormat(typ.sym.cgDeclFrmt, [name, desc, baseType])
-  if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props:
-    result.add "#pragma pack(pop)\L"
 
 proc getTupleDesc(m: BModule; typ: PType, name: Rope,
                   check: var IntSet): Rope =
-  result = "$1 $2 {$n" % [structOrUnion(typ), name]
-  var desc: Rope = ""
-  for i, a in typ.ikids:
-    desc.addf("$1 Field$2;$n",
-         [getTypeDescAux(m, a, check, dkField), rope(i)])
-  if desc == "": result.add("char dummy;\L")
-  else: result.add(desc)
-  result.add("};\L")
+  result = newBuilder("")
+  result.addStruct(m, typ, name, ""):
+    for i, a in typ.ikids:
+      result.addField(
+        name = "Field" & $i,
+        typ = getTypeDescAux(m, a, check, dkField))
 
 proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
   # A helper proc for handling cppimport patterns, involving numeric
@@ -929,12 +860,11 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
   if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
   let sig = hashType(origTyp, m.config)
 
-  result = "" # todo move `result = getTypePre(m, t, sig)` here ?
+  result = getTypePre(m, t, sig)
   defer: # defer is the simplest in this case
     if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
       addAbiCheck(m, t, result)
 
-  result = getTypePre(m, t, sig)
   if result != "" and t.kind != tyOpenArray:
     excl(check, t.id)
     if kind == dkRefParam or kind == dkRefGenericParam and origTyp.kind == tyGenericInst:
@@ -1037,18 +967,14 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
       m.typeCache[sig] = result & seqStar(m)
       if not isImportedType(t):
         if skipTypes(t.elementType, typedescInst).kind != tyEmpty:
-          const
-            cppSeq = "struct $2 : #TGenericSeq {$n"
-            cSeq = "struct $2 {$n" &
-                  "  #TGenericSeq Sup;$n"
-          if m.compileToCpp:
-            appcg(m, m.s[cfsSeqTypes],
-                cppSeq & "  $1 data[SEQ_DECL_SIZE];$n" &
-                "};$n", [getTypeDescAux(m, t.elementType, check, kind), result])
-          else:
-            appcg(m, m.s[cfsSeqTypes],
-                cSeq & "  $1 data[SEQ_DECL_SIZE];$n" &
-                "};$n", [getTypeDescAux(m, t.elementType, check, kind), result])
+          var struct = newBuilder("")
+          let baseType = cgsymValue(m, "TGenericSeq")
+          struct.addSimpleStruct(m, name = result, baseType = baseType):
+            struct.addField(
+              name = "data",
+              typ = getTypeDescAux(m, t.elementType, check, kind),
+              isFlexArray = true)
+          m.s[cfsSeqTypes].add struct
         else:
           result = rope("TGenericSeq")
       result.add(seqStar(m))
@@ -1220,7 +1146,7 @@ proc parseVFunctionDecl(val: string; name, params, retType, superCall: var strin
 
   params = "(" & params & ")"
 
-proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl : bool = false) =
+proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl: bool = false) =
   assert sfCppMember * prc.flags != {}
   let isCtor = sfConstructor in prc.flags
   var check = initIntSet()
@@ -1257,7 +1183,7 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
     superCall = ""
   else:
     if not isCtor:
-      prc.loc.r = "$1$2(@)" % [memberOp, name]
+      prc.loc.snippet = "$1$2(@)" % [memberOp, name]
     elif superCall != "":
       superCall = " : " & superCall
 
@@ -1278,7 +1204,7 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false)
   # handle the 2 options for hotcodereloading codegen - function pointer
   # (instead of forward declaration) or header for function body with "_actual" postfix
   let asPtrStr = rope(if asPtr: "_PTR" else: "")
-  var name = prc.loc.r
+  var name = prc.loc.snippet
   if not asPtr and isReloadable(m, prc):
     name.add("_actual")
   # careful here! don't access ``prc.ast`` as that could reload large parts of
@@ -1418,13 +1344,13 @@ proc genObjectFields(m: BModule; typ, origType: PType, n: PNode, expr: Rope;
     var tmp = discriminatorTableName(m, typ, field)
     var L = lengthOrd(m.config, field.typ)
     assert L > 0
-    if field.loc.r == "": fillObjectFields(m, typ)
+    if field.loc.snippet == "": fillObjectFields(m, typ)
     if field.loc.t == nil:
       internalError(m.config, n.info, "genObjectFields")
     m.s[cfsTypeInit3].addf("$1.kind = 3;$n" &
         "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
         "$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
-        "$1.len = $7;$n", [expr, getTypeDesc(m, origType, dkVar), field.loc.r,
+        "$1.len = $7;$n", [expr, getTypeDesc(m, origType, dkVar), field.loc.snippet,
                            genTypeInfoV1(m, field.typ, info),
                            makeCString(field.name.s),
                            tmp, rope(L)])
@@ -1456,13 +1382,13 @@ proc genObjectFields(m: BModule; typ, origType: PType, n: PNode, expr: Rope;
     # Do not produce code for void types
     if isEmptyType(field.typ): return
     if field.bitsize == 0:
-      if field.loc.r == "": fillObjectFields(m, typ)
+      if field.loc.snippet == "": fillObjectFields(m, typ)
       if field.loc.t == nil:
         internalError(m.config, n.info, "genObjectFields")
       m.s[cfsTypeInit3].addf("$1.kind = 1;$n" &
           "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
           "$1.name = $5;$n", [expr, getTypeDesc(m, origType, dkVar),
-          field.loc.r, genTypeInfoV1(m, field.typ, info), makeCString(field.name.s)])
+          field.loc.snippet, genTypeInfoV1(m, field.typ, info), makeCString(field.name.s)])
   else: internalError(m.config, n.info, "genObjectFields")
 
 proc genObjectInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) =
@@ -1472,7 +1398,7 @@ proc genObjectInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo
                       typeToString(typ))
   genTypeInfoAux(m, typ, origType, name, info)
   var tmp = getNimNode(m)
-  if not isImportedType(typ):
+  if (not isImportedType(typ)) or tfCompleteStruct in typ.flags:
     genObjectFields(m, typ, origType, typ.n, tmp, info)
   m.s[cfsTypeInit3].addf("$1.node = &$2;$n", [tiNameForHcr(m, name), tmp])
   var t = typ.baseClass
@@ -1567,7 +1493,7 @@ include ccgtrav
 proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
   genProc(m, s)
   m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
-     [result, s.loc.r])
+     [result, s.loc.snippet])
 
 proc declareNimType(m: BModule; name: string; str: Rope, module: int) =
   let nr = rope(name)
@@ -1655,10 +1581,10 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp; result:
       let wrapper = generateRttiDestructor(m.g.graph, t, theProc.owner, attachedDestructor,
                 theProc.info, m.idgen, theProc)
       genProc(m, wrapper)
-      result.add wrapper.loc.r
+      result.add wrapper.loc.snippet
     else:
       genProc(m, theProc)
-      result.add theProc.loc.r
+      result.add theProc.loc.snippet
 
     when false:
       if not canFormAcycle(m.g.graph, t) and op == attachedTrace:
@@ -1706,7 +1632,7 @@ proc genVTable(seqs: seq[PSym]): string =
   result = "{"
   for i in 0..<seqs.len:
     if i > 0: result.add ", "
-    result.add "(void *) " & seqs[i].loc.r
+    result.add "(void *) " & seqs[i].loc.snippet
   result.add "}"
 
 proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) =
@@ -1861,8 +1787,7 @@ proc typeToC(t: PType): string =
   ## to be unique.
   let s = typeToString(t)
   result = newStringOfCap(s.len)
-  for i in 0..<s.len:
-    let c = s[i]
+  for c in s:
     case c
     of 'a'..'z':
       result.add c
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index da55df45d..c0e574186 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -90,6 +90,9 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
     if s.typ.sym != nil and sfForward in s.typ.sym.flags:
       # forwarded objects are *always* passed by pointers for consistency!
       result = true
+    elif s.typ.kind == tySink and conf.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
+      # bug #23354:
+      result = false
     elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3):
       result = true           # requested anyway
     elif (tfFinal in pt.flags) and (pt[0] == nil):
@@ -122,7 +125,7 @@ proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
   var name = s.name.s
   if makeUnique:
     name = makeUnique(m, s, name)
-  "N" & encodeName(s.owner.name.s) & encodeName(name) & "E"
+  "N" & encodeName(s.skipGenericOwner.name.s) & encodeName(name) & "E"
 
 proc encodeType*(m: BModule; t: PType): string =
   result = ""
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index e4ba41614..091f5c842 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -15,7 +15,7 @@ import
   ccgutils, ropes, wordrecg, treetab, cgmeth,
   rodutils, renderer, cgendata, aliases,
   lowerings, ndi, lineinfos, pathutils, transf,
-  injectdestructors, astmsgs, modulepaths, backendpragmas,
+  injectdestructors, astmsgs, modulepaths, pushpoppragmas,
   mangleutils
 
 from expanddefaults import caseObjDefaultBranch
@@ -33,6 +33,12 @@ import std/strutils except `%`, addf # collides with ropes.`%`
 from ic / ic import ModuleBackendFlag
 import std/[dynlib, math, tables, sets, os, intsets, hashes]
 
+const
+  # we use some ASCII control characters to insert directives that will be converted to real code in a postprocessing pass
+  postprocessDirStart = '\1'
+  postprocessDirSep = '\31'
+  postprocessDirEnd = '\23'
+
 when not declared(dynlib.libCandidates):
   proc libCandidates(s: string, dest: var seq[string]) =
     ## given a library name pattern `s` write possible library names to `dest`.
@@ -66,8 +72,7 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
 
 proc initLoc(k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}): TLoc =
   result = TLoc(k: k, storage: s, lode: lode,
-               r: "", flags: flags
-  )
+                snippet: "", flags: flags)
 
 proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} =
   # fills the loc if it is not already initialized
@@ -75,7 +80,7 @@ proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.i
     a.k = k
     a.lode = lode
     a.storage = s
-    if a.r == "": a.r = r
+    if a.snippet == "": a.snippet = r
 
 proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) {.inline.} =
   # fills the loc if it is not already initialized
@@ -267,24 +272,28 @@ proc safeLineNm(info: TLineInfo): int =
   result = toLinenumber(info)
   if result < 0: result = 0 # negative numbers are not allowed in #line
 
-proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
+proc genPostprocessDir(field1, field2, field3: string): string =
+  result = postprocessDirStart & field1 & postprocessDirSep & field2 & postprocessDirSep & field3 & postprocessDirEnd
+
+proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; conf: ConfigRef) =
   assert line >= 0
   if optLineDir in conf.options and line > 0:
-    r.addf("\n#line $2 $1\n",
-        [rope(makeSingleLineCString(filename)), rope(line)])
+    if fileIdx == InvalidFileIdx:
+      r.add(rope("\n#line " & $line & " \"generated_not_to_break_here\"\n"))
+    else:
+      r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
 
-proc genCLineDir(r: var Rope, filename: string, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
+proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
   assert line >= 0
   if optLineDir in p.config.options and line > 0:
-    if lastFileIndex == info.fileIndex:
-        r.addf("\n#line $1\n", [rope(line)])
+    if fileIdx == InvalidFileIdx:
+      r.add(rope("\n#line " & $line & " \"generated_not_to_break_here\"\n"))
     else:
-      r.addf("\n#line $2 $1\n",
-        [rope(makeSingleLineCString(filename)), rope(line)])
+      r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
 
 proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
   if optLineDir in conf.options:
-    genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
+    genCLineDir(r, info.fileIndex, info.safeLineNm, conf)
 
 proc freshLineInfo(p: BProc; info: TLineInfo): bool =
   if p.lastLineInfo.line != info.line or
@@ -299,7 +308,7 @@ proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
   if optLineDir in conf.options:
     let lastFileIndex = p.lastLineInfo.fileIndex
     if freshLineInfo(p, info):
-      genCLineDir(r, toFullPath(conf, info), info.safeLineNm, p, info, lastFileIndex)
+      genCLineDir(r, info.fileIndex, info.safeLineNm, p, info, lastFileIndex)
 
 proc genLineDir(p: BProc, t: PNode) =
   if p == p.module.preInitProc: return
@@ -310,16 +319,11 @@ proc genLineDir(p: BProc, t: PNode) =
   let lastFileIndex = p.lastLineInfo.fileIndex
   let freshLine = freshLineInfo(p, t.info)
   if freshLine:
-    genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p, t.info, lastFileIndex)
+    genCLineDir(p.s(cpsStmts), t.info.fileIndex, line, p, t.info, lastFileIndex)
   if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
       (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
       if freshLine:
-        if lastFileIndex == t.info.fileIndex:
-          linefmt(p, cpsStmts, "nimln_($1);",
-              [line])
-        else:
-          linefmt(p, cpsStmts, "nimlf_($1, $2);",
-              [line, quotedFilename(p.config, t.info)])
+        line(p, cpsStmts, genPostprocessDir("nimln", $line, $t.info.fileIndex.int32))
 
 proc accessThreadLocalVar(p: BProc, s: PSym)
 proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
@@ -336,15 +340,15 @@ proc getTempName(m: BModule): Rope =
 proc rdLoc(a: TLoc): Rope =
   # 'read' location (deref if indirect)
   if lfIndirect in a.flags:
-    result = "(*" & a.r & ")"
+    result = "(*" & a.snippet & ")"
   else:
-    result = a.r
+    result = a.snippet
 
 proc addRdLoc(a: TLoc; result: var Rope) =
   if lfIndirect in a.flags:
-    result.add "(*" & a.r & ")"
+    result.add "(*" & a.snippet & ")"
   else:
-    result.add a.r
+    result.add a.snippet
 
 proc lenField(p: BProc): Rope {.inline.} =
   result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
@@ -369,6 +373,7 @@ proc dataField(p: BProc): Rope =
 
 proc genProcPrototype(m: BModule, sym: PSym)
 
+include cbuilder
 include ccgliterals
 include ccgtypes
 
@@ -381,22 +386,22 @@ template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
 
 proc addAddrLoc(conf: ConfigRef; a: TLoc; result: var Rope) =
   if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
-    result.add "(&" & a.r & ")"
+    result.add "(&" & a.snippet & ")"
   else:
-    result.add a.r
+    result.add a.snippet
 
 proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
   if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
-    result = "(&" & a.r & ")"
+    result = "(&" & a.snippet & ")"
   else:
-    result = a.r
+    result = a.snippet
 
 proc byRefLoc(p: BProc; a: TLoc): Rope =
   if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a) == skParam) != ctArray and not
       p.module.compileToCpp:
-    result = "(&" & a.r & ")"
+    result = "(&" & a.snippet & ")"
   else:
-    result = a.r
+    result = a.snippet
 
 proc rdCharLoc(a: TLoc): Rope =
   # read a location that may need a char-cast:
@@ -407,7 +412,9 @@ proc rdCharLoc(a: TLoc): Rope =
 type
   TAssignmentFlag = enum
     needToCopy
+    needToCopySinkParam
     needTempForOpenArray
+    needAssignCall
   TAssignmentFlags = set[TAssignmentFlag]
 
 proc genObjConstr(p: BProc, e: PNode, d: var TLoc)
@@ -476,9 +483,12 @@ include ccgreset
 proc resetLoc(p: BProc, loc: var TLoc) =
   let containsGcRef = optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(loc.t)
   let typ = skipTypes(loc.t, abstractVarRange)
-  if isImportedCppType(typ): return
+  if isImportedCppType(typ): 
+    var didGenTemp = false
+    linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(loc), genCppInitializer(p.module, p, typ, didGenTemp)])
+    return
   if optSeqDestructors in p.config.globalOptions and typ.kind in {tyString, tySequence}:
-    assert loc.r != ""
+    assert loc.snippet != ""
 
     let atyp = skipTypes(loc.t, abstractInst)
     if atyp.kind in {tyVar, tyLent}:
@@ -488,7 +498,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
   elif not isComplexValueType(typ):
     if containsGcRef:
       var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
-      nilLoc.r = rope("NIM_NIL")
+      nilLoc.snippet = rope("NIM_NIL")
       genRefAssign(p, loc, nilLoc)
     else:
       linefmt(p, cpsStmts, "$1 = 0;$n", [rdLoc(loc)])
@@ -526,7 +536,7 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
   elif not isComplexValueType(typ):
     if containsGarbageCollectedRef(loc.t):
       var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
-      nilLoc.r = rope("NIM_NIL")
+      nilLoc.snippet = rope("NIM_NIL")
       genRefAssign(p, loc, nilLoc)
     else:
       linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
@@ -554,13 +564,14 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
 
 proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
   inc(p.labels)
-  result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
+  result = TLoc(snippet: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
                 storage: OnStack, flags: {})
   if p.module.compileToCpp and isOrHasImportedCppType(t):
-    linefmt(p, cpsLocals, "$1 $2$3;$n", [getTypeDesc(p.module, t, dkVar), result.r,
-      genCppInitializer(p.module, p, t)])
+    var didGenTemp = false
+    linefmt(p, cpsLocals, "$1 $2$3;$n", [getTypeDesc(p.module, t, dkVar), result.snippet,
+      genCppInitializer(p.module, p, t, didGenTemp)])
   else:
-    linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r])
+    linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.snippet])
   constructLoc(p, result, not needsInit)
   when false:
     # XXX Introduce a compiler switch in order to detect these easily.
@@ -573,16 +584,16 @@ proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
 
 proc getTempCpp(p: BProc, t: PType, value: Rope): TLoc =
   inc(p.labels)
-  result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
+  result = TLoc(snippet: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
                 storage: OnStack, flags: {})
-  linefmt(p, cpsStmts, "auto $1 = $2;$n", [result.r, value])
+  linefmt(p, cpsStmts, "auto $1 = $2;$n", [result.snippet, value])
 
 proc getIntTemp(p: BProc): TLoc =
   inc(p.labels)
-  result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp,
+  result = TLoc(snippet: "T" & rope(p.labels) & "_", k: locTemp,
                 storage: OnStack, lode: lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt),
                 flags: {})
-  linefmt(p, cpsLocals, "NI $1;$n", [result.r])
+  linefmt(p, cpsLocals, "NI $1;$n", [result.snippet])
 
 proc localVarDecl(p: BProc; n: PNode): Rope =
   result = ""
@@ -604,9 +615,9 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
     if sfVolatile in s.flags: result.add(" volatile")
     if sfNoalias in s.flags: result.add(" NIM_NOALIAS")
     result.add(" ")
-    result.add(s.loc.r)
+    result.add(s.loc.snippet)
   else:
-    result = runtimeFormat(s.cgDeclFrmt, [result, s.loc.r])
+    result = runtimeFormat(s.cgDeclFrmt, [result, s.loc.snippet])
 
 proc assignLocalVar(p: BProc, n: PNode) =
   #assert(s.loc.k == locNone) # not yet assigned
@@ -615,7 +626,8 @@ proc assignLocalVar(p: BProc, n: PNode) =
   let nl = if optLineDir in p.config.options: "" else: "\n"
   var decl = localVarDecl(p, n)
   if p.module.compileToCpp and isOrHasImportedCppType(n.typ):
-    decl.add genCppInitializer(p.module, p, n.typ)
+    var didGenTemp = false
+    decl.add genCppInitializer(p.module, p, n.typ, didGenTemp)
   decl.add ";" & nl
   line(p, cpsLocals, decl)
 
@@ -646,22 +658,11 @@ proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) =
     if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
   else:
     if value != "":
-      decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value])
+      decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.snippet, value])
     else:
-      decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
+      decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.snippet])
 
-proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope)
-
-proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) =
-  let s = vn.sym
-  fillBackendName(p.module, s)
-  fillLoc(s.loc, locGlobalVar, vn, OnHeap)
-  var decl: Rope = ""
-  let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
-  genGlobalVarDecl(p, vn, td, "", decl)
-  decl.add " " & $s.loc.r
-  genCppVarForCtor(p, value, decl)
-  p.module.s[cfsVars].add decl
+proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope; didGenTemp: var bool)
 
 proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
   let s = n.sym
@@ -675,7 +676,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
     if q != nil and not containsOrIncl(q.declaredThings, s.id):
       varInDynamicLib(q, s)
     else:
-      s.loc.r = mangleDynLibProc(s)
+      s.loc.snippet = mangleDynLibProc(s)
     if value != "":
       internalError(p.config, n.info, ".dynlib variables cannot have a value")
     return
@@ -706,19 +707,31 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
             # [^0]: https://en.cppreference.com/w/cpp/language/aggregate_initialization
             # [^1]: https://cplusplus.github.io/CWG/issues/1518.html
             # [^2]: https://eel.is/c++draft/over.match.ctor
-            decl.addf(" $1;$n", [s.loc.r])
+            decl.addf(" $1;$n", [s.loc.snippet])
           else:
-            decl.addf(" $1 = $2;$n", [s.loc.r, value])
+            decl.addf(" $1 = $2;$n", [s.loc.snippet, value])
         else:
-          decl.addf(" $1;$n", [s.loc.r])
+          decl.addf(" $1;$n", [s.loc.snippet])
 
       p.module.s[cfsVars].add(decl)
   if p.withinLoop > 0 and value == "":
     # fixes tests/run/tzeroarray:
     resetLoc(p, s.loc)
 
+proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode; didGenTemp: var bool) =
+  let s = vn.sym
+  fillBackendName(p.module, s)
+  fillLoc(s.loc, locGlobalVar, vn, OnHeap)
+  var decl: Rope = ""
+  let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
+  genGlobalVarDecl(p, vn, td, "", decl)
+  decl.add " " & $s.loc.snippet
+  genCppVarForCtor(p, value, decl, didGenTemp)
+  if didGenTemp:  return # generated in the caller
+  p.module.s[cfsVars].add decl
+
 proc assignParam(p: BProc, s: PSym, retType: PType) =
-  assert(s.loc.r != "")
+  assert(s.loc.snippet != "")
   scopeMangledParam(p, s)
 
 proc fillProcLoc(m: BModule; n: PNode) =
@@ -744,6 +757,7 @@ proc intLiteral(i: BiggestInt; result: var Rope)
 proc genLiteral(p: BProc, n: PNode; result: var Rope)
 proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
 proc raiseExit(p: BProc)
+proc raiseExitCleanup(p: BProc, destroy: string)
 
 proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
   result = initLoc(locNone, e, OnUnknown, flags)
@@ -770,15 +784,11 @@ $1define nimfr_(proc, file) \
   TFrame FR_; \
   FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; #nimFrame(&FR_);
 
-  $1define nimfrs_(proc, file, slots, length) \
-    struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename;NI len;VarSlot s[slots];} FR_; \
-    FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; #nimFrame((TFrame*)&FR_);
+$1define nimln_(n) \
+  FR_.line = n;
 
-  $1define nimln_(n) \
-    FR_.line = n;
-
-  $1define nimlf_(n, file) \
-    FR_.line = n; FR_.filename = file;
+$1define nimlf_(n, file) \
+  FR_.line = n; FR_.filename = file;
 
 """
   if p.module.s[cfsFrameDefines].len == 0:
@@ -842,7 +852,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
       p.options.excl optStackTrace
       p.flags.incl nimErrorFlagDisabled
       var dest: TLoc = initLoc(locTemp, lib.path, OnStack)
-      dest.r = getTempName(m)
+      dest.snippet = getTempName(m)
       appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
            [getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
       expr(p, lib.path, dest)
@@ -860,7 +870,7 @@ proc mangleDynLibProc(sym: PSym): Rope =
   # we have to build this as a single rope in order not to trip the
   # optimization in genInfixCall, see test tests/cpp/t8241.nim
   if sfCompilerProc in sym.flags:
-    # NOTE: sym.loc.r is the external name!
+    # NOTE: sym.loc.snippet is the external name!
     result = rope(sym.name.s)
   else:
     result = rope(strutils.`%`("Dl_$1_", $sym.id))
@@ -868,10 +878,10 @@ proc mangleDynLibProc(sym: PSym): Rope =
 proc symInDynamicLib(m: BModule, sym: PSym) =
   var lib = sym.annex
   let isCall = isGetProcAddr(lib)
-  var extname = sym.loc.r
+  var extname = sym.loc.snippet
   if not isCall: loadDynamicLib(m, lib)
   var tmp = mangleDynLibProc(sym)
-  sym.loc.r = tmp             # from now on we only need the internal name
+  sym.loc.snippet = tmp             # from now on we only need the internal name
   sym.typ.sym = nil           # generate a new name
   inc(m.labels, 2)
   if isCall:
@@ -898,24 +908,24 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
     appcg(m, m.s[cfsDynLibInit],
         "\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
         [tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)])
-  m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
+  m.s[cfsVars].addf("$2 $1;$n", [sym.loc.snippet, getTypeDesc(m, sym.loc.t, dkVar)])
 
 proc varInDynamicLib(m: BModule, sym: PSym) =
   var lib = sym.annex
-  var extname = sym.loc.r
+  var extname = sym.loc.snippet
   loadDynamicLib(m, lib)
   incl(sym.loc.flags, lfIndirect)
   var tmp = mangleDynLibProc(sym)
-  sym.loc.r = tmp             # from now on we only need the internal name
+  sym.loc.snippet = tmp             # from now on we only need the internal name
   inc(m.labels, 2)
   appcg(m, m.s[cfsDynLibInit],
       "$1 = ($2*) #nimGetProcAddr($3, $4);$n",
       [tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)])
   m.s[cfsVars].addf("$2* $1;$n",
-      [sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
+      [sym.loc.snippet, getTypeDesc(m, sym.loc.t, dkVar)])
 
 proc symInDynamicLibPartial(m: BModule, sym: PSym) =
-  sym.loc.r = mangleDynLibProc(sym)
+  sym.loc.snippet = mangleDynLibProc(sym)
   sym.typ.sym = nil           # generate a new name
 
 proc cgsymImpl(m: BModule; sym: PSym) {.inline.} =
@@ -938,7 +948,7 @@ proc cgsymValue(m: BModule, name: string): Rope =
     cgsymImpl m, sym
   else:
     rawMessage(m.config, errGenerated, "system module needs: " & name)
-  result = sym.loc.r
+  result = sym.loc.snippet
   if m.hcrOn and sym != nil and sym.kind in {skProc..skIterator}:
     result.addActualSuffixForHCR(m.module, sym)
 
@@ -1065,7 +1075,11 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
       if result != Unknown: return result
   of nkAsgn, nkFastAsgn, nkSinkAsgn:
     if n[0].kind == nkSym and n[0].sym.kind == skResult:
-      if not containsResult(n[1]): result = InitSkippable
+      if not containsResult(n[1]):
+        if allPathsAsgnResult(p, n[1]) == InitRequired:
+          result = InitRequired
+        else:
+          result = InitSkippable
       else: result = InitRequired
     elif containsResult(n):
       result = InitRequired
@@ -1143,6 +1157,10 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
         allPathsInBranch(n[i])
   of nkRaiseStmt:
     result = InitRequired
+  of nkChckRangeF, nkChckRange64, nkChckRange:
+    # TODO: more checks might need to be covered like overflow, indexDefect etc.
+    # bug #22852
+    result = InitRequired
   else:
     for i in 0..<n.safeLen:
       allPathsInBranch(n[i])
@@ -1197,7 +1215,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
       else:
         # declare the result symbol:
         assignLocalVar(p, resNode)
-        assert(res.loc.r != "")
+        assert(res.loc.snippet != "")
         if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
             allPathsAsgnResult(p, procBody) == InitSkippable:
           # In an ideal world the codegen could rely on injectdestructors doing its job properly
@@ -1209,7 +1227,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
     elif sfConstructor in prc.flags:
       resNode.sym.loc.flags.incl lfIndirect
       fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
-      prc.loc.r = getTypeDesc(m, resNode.sym.loc.t, dkVar)
+      prc.loc.snippet = getTypeDesc(m, resNode.sym.loc.t, dkVar)
     else:
       fillResult(p.config, resNode, prc.typ)
       assignParam(p, res, prc.typ.returnType)
@@ -1274,7 +1292,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
   m.s[cfsProcs].add(generatedProc)
   if isReloadable(m, prc):
     m.s[cfsDynLibInit].addf("\t$1 = ($3) hcrRegisterProc($4, \"$1\", (void*)$2);$n",
-         [prc.loc.r, prc.loc.r & "_actual", getProcTypeCast(m, prc), getModuleDllPath(m, prc)])
+         [prc.loc.snippet, prc.loc.snippet & "_actual", getProcTypeCast(m, prc), getModuleDllPath(m, prc)])
 
 proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
   result = (sfCompileToCpp in m.module.flags and
@@ -1334,7 +1352,7 @@ proc genProcNoForward(m: BModule, prc: PSym) =
       # the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded)
       if isReloadable(q, prc):
         q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
-            [prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
+            [prc.loc.snippet, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
     else:
       symInDynamicLibPartial(m, prc)
   elif prc.typ.callConv == ccInline:
@@ -1351,8 +1369,8 @@ proc genProcNoForward(m: BModule, prc: PSym) =
       #elif {sfExportc, sfImportc} * prc.flags == {}:
       #  # reset name to restore consistency in case of hashing collisions:
       #  echo "resetting ", prc.id, " by ", m.module.name.s
-      #  prc.loc.r = nil
-      #  prc.loc.r = mangleName(m, prc)
+      #  prc.loc.snippet = nil
+      #  prc.loc.snippet = mangleName(m, prc)
       genProcPrototype(m, prc)
       genProcAux(m, prc)
   elif sfImportc notin prc.flags:
@@ -1364,7 +1382,7 @@ proc genProcNoForward(m: BModule, prc: PSym) =
     if isReloadable(m, prc) and prc.id notin m.declaredProtos and
       q != nil and q.module.id != m.module.id:
       m.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
-           [prc.loc.r, getProcTypeCast(m, prc), getModuleDllPath(m, prc)])
+           [prc.loc.snippet, getProcTypeCast(m, prc), getModuleDllPath(m, prc)])
     genProcPrototype(m, prc)
     if q != nil and not containsOrIncl(q.declaredThings, prc.id):
       # make sure there is a "prototype" in the external module
@@ -1417,7 +1435,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
     return
   if sym.owner.id != m.module.id:
     # else we already have the symbol generated!
-    assert(sym.loc.r != "")
+    assert(sym.loc.snippet != "")
     incl(m.declaredThings, sym.id)
     if sfThread in sym.flags:
       declareThreadVar(m, sym, true)
@@ -1431,9 +1449,9 @@ proc genVarPrototype(m: BModule, n: PNode) =
       if sfRegister in sym.flags: m.s[cfsVars].add(" register")
       if sfVolatile in sym.flags: m.s[cfsVars].add(" volatile")
       if sfNoalias in sym.flags: m.s[cfsVars].add(" NIM_NOALIAS")
-      m.s[cfsVars].addf(" $1;$n", [sym.loc.r])
+      m.s[cfsVars].addf(" $1;$n", [sym.loc.snippet])
       if m.hcrOn: m.initProc.procSec(cpsLocals).addf(
-        "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
+        "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.snippet,
         getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(m, sym)])
 
 proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
@@ -1466,15 +1484,13 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
 
 proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope =
   ## Returns a mangled module name.
-  result = ""
-  result.add mangleModuleName(conf, filename).mangle
+  result = mangleModuleName(conf, filename).mangle
 
 proc getSomeNameForModule(m: BModule): Rope =
   ## Returns a mangled module name.
   assert m.module.kind == skModule
   assert m.module.owner.kind == skPackage
-  result = ""
-  result.add mangleModuleName(m.g.config, m.filename).mangle
+  result = mangleModuleName(m.g.config, m.filename).mangle
 
 proc getSomeInitName(m: BModule, suffix: string): Rope =
   if not m.hcrOn:
@@ -1810,7 +1826,7 @@ proc genDatInitCode(m: BModule) =
 
   # we don't want to break into such init code - could happen if a line
   # directive from a function written by the user spills after itself
-  genCLineDir(prc, "generated_not_to_break_here", 999999, m.config)
+  genCLineDir(prc, InvalidFileIdx, 999999, m.config)
 
   for i in cfsTypeInit1..cfsDynLibInit:
     if m.s[i].len != 0:
@@ -1832,11 +1848,11 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
 
   var extname = prefix & sym
   var tmp = mangleDynLibProc(prc)
-  prc.loc.r = tmp
+  prc.loc.snippet = tmp
   prc.typ.sym = nil
 
   if not containsOrIncl(m.declaredThings, prc.id):
-    m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, dkVar)])
+    m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.snippet, getTypeDesc(m, prc.loc.t, dkVar)])
 
   result = "\t$1 = ($2) $3($4, $5);$n" %
       [tmp, getTypeDesc(m, prc.typ, dkVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
@@ -1851,7 +1867,7 @@ proc genInitCode(m: BModule) =
     [rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname]
   # we don't want to break into such init code - could happen if a line
   # directive from a function written by the user spills after itself
-  genCLineDir(prc, "generated_not_to_break_here", 999999, m.config)
+  genCLineDir(prc, InvalidFileIdx, 999999, m.config)
   if m.typeNodes > 0:
     if m.hcrOn:
       appcg(m, m.s[cfsTypeInit1], "\t#TNimNode* $1;$N", [m.typeNodesName])
@@ -1921,9 +1937,6 @@ proc genInitCode(m: BModule) =
 
     if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
       prc.add(deinitFrame(m.initProc))
-  elif m.config.exc == excGoto:
-    if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
-      m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
 
   prc.addf("}$N", [])
 
@@ -1966,6 +1979,40 @@ proc genInitCode(m: BModule) =
 
   registerModuleToMain(m.g, m)
 
+proc postprocessCode(conf: ConfigRef, r: var Rope) =
+  # find the first directive
+  var f = r.find(postprocessDirStart)
+  if f == -1:
+    return
+
+  var
+    nimlnDirLastF = ""
+
+  var res: Rope = r.substr(0, f - 1)
+  while f != -1:
+    var
+      e = r.find(postprocessDirEnd, f + 1)
+      dir = r.substr(f + 1, e - 1).split(postprocessDirSep)
+    case dir[0]
+    of "nimln":
+      if dir[2] == nimlnDirLastF:
+        res.add("nimln_(" & dir[1] & ");")
+      else:
+        res.add("nimlf_(" & dir[1] & ", " & quotedFilename(conf, dir[2].parseInt.FileIndex) & ");")
+        nimlnDirLastF = dir[2]
+    else:
+      raiseAssert "unexpected postprocess directive"
+
+    # find the next directive
+    f = r.find(postprocessDirStart, e + 1)
+    # copy the code until the next directive
+    if f != -1:
+      res.add(r.substr(e + 1, f - 1))
+    else:
+      res.add(r.substr(e + 1))
+
+  r = res
+
 proc genModule(m: BModule, cfile: Cfile): Rope =
   var moduleIsEmpty = true
 
@@ -1994,9 +2041,17 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
   if m.config.cppCustomNamespace.len > 0:
     closeNamespaceNim(result)
 
+  if optLineDir in m.config.options:
+    var srcFileDefs = ""
+    for fi in 0..m.config.m.fileInfos.high:
+      srcFileDefs.add("#define FX_" & $fi & " " & makeSingleLineCString(toFullPath(m.config, fi.FileIndex)) & "\n")
+    result = srcFileDefs & result
+
   if moduleIsEmpty:
     result = ""
 
+  postprocessCode(m.config, result)
+
 proc initProcOptions(m: BModule): TOptions =
   let opts = m.config.options
   if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
@@ -2202,7 +2257,7 @@ proc generateLibraryDestroyGlobals(graph: ModuleGraph; m: BModule; body: PNode;
   result.typ = newProcType(m.module.info, m.idgen, m.module.owner)
   result.typ.callConv = ccCDecl
   incl result.flags, sfExportc
-  result.loc.r = "NimDestroyGlobals"
+  result.loc.snippet = "NimDestroyGlobals"
   if isDynlib:
     incl(result.loc.flags, lfExportLib)
 
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 9f71a8292..5368e9dc7 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -88,7 +88,7 @@ type
     options*: TOptions        # options that should be used for code
                               # generation; this is the same as prc.options
                               # unless prc == nil
-    optionsStack*: seq[TOptions]
+    optionsStack*: seq[(TOptions, TNoteKinds)]
     module*: BModule          # used to prevent excessive parameter passing
     withinLoop*: int          # > 0 if we are within a loop
     splitDecls*: int          # > 0 if we are in some context for C++ that
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index b132c6049..ca97d0494 100644
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -133,7 +133,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
   if disp.typ.callConv == ccInline: disp.typ.callConv = ccNimCall
   disp.ast = copyTree(s.ast)
   disp.ast[bodyPos] = newNodeI(nkEmpty, s.info)
-  disp.loc.r = ""
+  disp.loc.snippet = ""
   if s.typ.returnType != nil:
     if disp.ast.len > resultPos:
       disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen)
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index c1f525488..8bdd04ca7 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -36,13 +36,6 @@
 #  else:
 #    return
 
-# The transformation should play well with lambdalifting, however depending
-# on situation, it can be called either before or after lambdalifting
-# transformation. As such we behave slightly differently, when accessing
-# iterator state, or using temp variables. If lambdalifting did not happen,
-# we just create local variables, so that they will be lifted further on.
-# Otherwise, we utilize existing env, created by lambdalifting.
-
 # Lambdalifting treats :state variable specially, it should always end up
 # as the first field in env. Currently C codegen depends on this behavior.
 
@@ -151,7 +144,6 @@ type
   Ctx = object
     g: ModuleGraph
     fn: PSym
-    stateVarSym: PSym # :state variable. nil if env already introduced by lambdalifting
     tmpResultSym: PSym # Used when we return, but finally has to interfere
     unrollFinallySym: PSym # Indicates that we're unrolling finally states (either exception happened or premature return)
     curExcSym: PSym # Current exception
@@ -168,16 +160,23 @@ type
     nearestFinally: int # Index of the nearest finally block. For try/except it
                     # is their finally. For finally it is parent finally. Otherwise -1
     idgen: IdGenerator
+    varStates: Table[ItemId, int] # Used to detect if local variable belongs to multiple states
+    stateVarSym: PSym # :state variable. nil if env already introduced by lambdalifting
+      # remove if -d:nimOptIters is default, treating it as always nil
+    nimOptItersEnabled: bool # tracks if -d:nimOptIters is enabled
+      # should be default when issues are fixed, see #24094
 
 const
   nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
             nkCommentStmt, nkMixinStmt, nkBindStmt} + procDefs
   emptyStateLabel = -1
+  localNotSeen = -1
+  localRequiresLifting = -2
 
 proc newStateAccess(ctx: var Ctx): PNode =
   if ctx.stateVarSym.isNil:
     result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)),
-        getStateField(ctx.g, ctx.fn), ctx.fn.info)
+      getStateField(ctx.g, ctx.fn), ctx.fn.info)
   else:
     result = newSymNode(ctx.stateVarSym)
 
@@ -195,7 +194,7 @@ proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
   result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.idgen, ctx.fn, ctx.fn.info)
   result.typ = typ
   result.flags.incl sfNoInit
-  assert(not typ.isNil)
+  assert(not typ.isNil, "Env var needs a type")
 
   if not ctx.stateVarSym.isNil:
     # We haven't gone through labmda lifting yet, so just create a local var,
@@ -214,6 +213,9 @@ proc newEnvVarAccess(ctx: Ctx, s: PSym): PNode =
   else:
     result = newSymNode(s)
 
+proc newTempVarAccess(ctx: Ctx, s: PSym): PNode =
+  result = newSymNode(s, ctx.fn.info)
+
 proc newTmpResultAccess(ctx: var Ctx): PNode =
   if ctx.tmpResultSym.isNil:
     ctx.tmpResultSym = ctx.newEnvVar(":tmpResult", ctx.fn.typ.returnType)
@@ -255,9 +257,26 @@ proc addGotoOut(n: PNode, gotoOut: PNode): PNode =
   if result.len == 0 or result[^1].kind != nkGotoState:
     result.add(gotoOut)
 
-proc newTempVar(ctx: var Ctx, typ: PType): PSym =
-  result = ctx.newEnvVar(":tmpSlLower" & $ctx.tempVarId, typ)
+proc newTempVarDef(ctx: Ctx, s: PSym, initialValue: PNode): PNode =
+  var v = initialValue
+  if v == nil:
+    v = ctx.g.emptyNode
+  newTree(nkVarSection, newTree(nkIdentDefs, newSymNode(s), ctx.g.emptyNode, v))
+
+proc newEnvVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode
+
+proc newTempVar(ctx: var Ctx, typ: PType, parent: PNode, initialValue: PNode = nil): PSym =
+  if ctx.nimOptItersEnabled:
+    result = newSym(skVar, getIdent(ctx.g.cache, ":tmpSlLower" & $ctx.tempVarId), ctx.idgen, ctx.fn, ctx.fn.info)
+  else:
+    result = ctx.newEnvVar(":tmpSlLower" & $ctx.tempVarId, typ)
   inc ctx.tempVarId
+  result.typ = typ
+  assert(not typ.isNil, "Temp var needs a type")
+  if ctx.nimOptItersEnabled:
+    parent.add(ctx.newTempVarDef(result, initialValue))
+  elif initialValue != nil:
+    parent.add(ctx.newEnvVarAsgn(result, initialValue))
 
 proc hasYields(n: PNode): bool =
   # TODO: This is very inefficient. It traverses the node, looking for nkYieldStmt.
@@ -429,8 +448,15 @@ proc exprToStmtList(n: PNode): tuple[s, res: PNode] =
 
   result.res = n
 
+proc newTempVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode =
+  if isEmptyType(v.typ):
+    result = v
+  else:
+    result = newTree(nkFastAsgn, ctx.newTempVarAccess(s), v)
+    result.info = v.info
 
 proc newEnvVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode =
+  # unused with -d:nimOptIters
   if isEmptyType(v.typ):
     result = v
   else:
@@ -438,10 +464,13 @@ proc newEnvVarAsgn(ctx: Ctx, s: PSym, v: PNode): PNode =
     result.info = v.info
 
 proc addExprAssgn(ctx: Ctx, output, input: PNode, sym: PSym) =
+  var input = input
   if input.kind == nkStmtListExpr:
     let (st, res) = exprToStmtList(input)
     output.add(st)
-    output.add(ctx.newEnvVarAsgn(sym, res))
+    input = res
+  if ctx.nimOptItersEnabled:
+    output.add(ctx.newTempVarAsgn(sym, input))
   else:
     output.add(ctx.newEnvVarAsgn(sym, input))
 
@@ -457,6 +486,12 @@ proc boolLit(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
   result = newIntLit(g, info, ord value)
   result.typ = getSysType(g, info, tyBool)
 
+proc captureVar(c: var Ctx, s: PSym) =
+  if c.varStates.getOrDefault(s.itemId) != localRequiresLifting:
+    c.varStates[s.itemId] = localRequiresLifting # Mark this variable for lifting
+    let e = getEnvParam(c.fn)
+    discard addField(e.typ.elementType, s, c.g.cache, c.idgen)
+
 proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
   result = n
   case n.kind
@@ -513,9 +548,9 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       var tmp: PSym = nil
       let isExpr = not isEmptyType(n.typ)
       if isExpr:
-        tmp = ctx.newTempVar(n.typ)
         result = newNodeI(nkStmtListExpr, n.info)
         result.typ = n.typ
+        tmp = ctx.newTempVar(n.typ, result)
       else:
         result = newNodeI(nkStmtList, n.info)
 
@@ -566,7 +601,11 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
         else:
           internalError(ctx.g.config, "lowerStmtListExpr(nkIf): " & $branch.kind)
 
-      if isExpr: result.add(ctx.newEnvVarAccess(tmp))
+      if isExpr:
+        if ctx.nimOptItersEnabled:
+          result.add(ctx.newTempVarAccess(tmp))
+        else:
+          result.add(ctx.newEnvVarAccess(tmp))
 
   of nkTryStmt, nkHiddenTryStmt:
     var ns = false
@@ -580,7 +619,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       if isExpr:
         result = newNodeI(nkStmtListExpr, n.info)
         result.typ = n.typ
-        let tmp = ctx.newTempVar(n.typ)
+        let tmp = ctx.newTempVar(n.typ, result)
 
         n[0] = ctx.convertExprBodyToAsgn(n[0], tmp)
         for i in 1..<n.len:
@@ -596,7 +635,10 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
           else:
             internalError(ctx.g.config, "lowerStmtListExpr(nkTryStmt): " & $branch.kind)
         result.add(n)
-        result.add(ctx.newEnvVarAccess(tmp))
+        if ctx.nimOptItersEnabled:
+          result.add(ctx.newTempVarAccess(tmp))
+        else:
+          result.add(ctx.newEnvVarAccess(tmp))
 
   of nkCaseStmt:
     var ns = false
@@ -609,9 +651,9 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       let isExpr = not isEmptyType(n.typ)
 
       if isExpr:
-        let tmp = ctx.newTempVar(n.typ)
         result = newNodeI(nkStmtListExpr, n.info)
         result.typ = n.typ
+        let tmp = ctx.newTempVar(n.typ, result)
 
         if n[0].kind == nkStmtListExpr:
           let (st, ex) = exprToStmtList(n[0])
@@ -628,7 +670,10 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
           else:
             internalError(ctx.g.config, "lowerStmtListExpr(nkCaseStmt): " & $branch.kind)
         result.add(n)
-        result.add(ctx.newEnvVarAccess(tmp))
+        if ctx.nimOptItersEnabled:
+          result.add(ctx.newTempVarAccess(tmp))
+        else:
+          result.add(ctx.newEnvVarAccess(tmp))
       elif n[0].kind == nkStmtListExpr:
         result = newNodeI(nkStmtList, n.info)
         let (st, ex) = exprToStmtList(n[0])
@@ -658,10 +703,14 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
           result.add(st)
           cond = ex
 
-        let tmp = ctx.newTempVar(cond.typ)
-        result.add(ctx.newEnvVarAsgn(tmp, cond))
+        let tmp = ctx.newTempVar(cond.typ, result, cond)
+        # result.add(ctx.newTempVarAsgn(tmp, cond))
 
-        var check = ctx.newEnvVarAccess(tmp)
+        var check: PNode
+        if ctx.nimOptItersEnabled:
+          check = ctx.newTempVarAccess(tmp)
+        else:
+          check = ctx.newEnvVarAccess(tmp)
         if n[0].sym.magic == mOr:
           check = ctx.g.newNotCall(check)
 
@@ -671,12 +720,18 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
           let (st, ex) = exprToStmtList(cond)
           ifBody.add(st)
           cond = ex
-        ifBody.add(ctx.newEnvVarAsgn(tmp, cond))
+        if ctx.nimOptItersEnabled:
+          ifBody.add(ctx.newTempVarAsgn(tmp, cond))
+        else:
+          ifBody.add(ctx.newEnvVarAsgn(tmp, cond))
 
         let ifBranch = newTree(nkElifBranch, check, ifBody)
         let ifNode = newTree(nkIfStmt, ifBranch)
         result.add(ifNode)
-        result.add(ctx.newEnvVarAccess(tmp))
+        if ctx.nimOptItersEnabled:
+          result.add(ctx.newTempVarAccess(tmp))
+        else:
+          result.add(ctx.newEnvVarAccess(tmp))
       else:
         for i in 0..<n.len:
           if n[i].kind == nkStmtListExpr:
@@ -685,9 +740,12 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
             n[i] = ex
 
           if n[i].kind in nkCallKinds: # XXX: This should better be some sort of side effect tracking
-            let tmp = ctx.newTempVar(n[i].typ)
-            result.add(ctx.newEnvVarAsgn(tmp, n[i]))
-            n[i] = ctx.newEnvVarAccess(tmp)
+            let tmp = ctx.newTempVar(n[i].typ, result, n[i])
+            # result.add(ctx.newTempVarAsgn(tmp, n[i]))
+            if ctx.nimOptItersEnabled:
+              n[i] = ctx.newTempVarAccess(tmp)
+            else:
+              n[i] = ctx.newEnvVarAccess(tmp)
 
         result.add(n)
 
@@ -703,6 +761,12 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
         let (st, ex) = exprToStmtList(c[^1])
         result.add(st)
         c[^1] = ex
+      for i in 0 .. c.len - 3:
+        if c[i].kind == nkSym:
+          let s = c[i].sym
+          if sfForceLift in s.flags:
+            ctx.captureVar(s)
+
       result.add(varSect)
 
   of nkDiscardStmt, nkReturnStmt, nkRaiseStmt:
@@ -1433,15 +1497,77 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
     for i in 0 ..< n.len:
       result[i] = preprocess(c, n[i])
 
+proc detectCapturedVars(c: var Ctx, n: PNode, stateIdx: int) =
+  case n.kind
+  of nkSym:
+    let s = n.sym
+    if s.kind in {skResult, skVar, skLet, skForVar, skTemp} and sfGlobal notin s.flags and s.owner == c.fn:
+      let vs = c.varStates.getOrDefault(s.itemId, localNotSeen)
+      if vs == localNotSeen: # First seing this variable
+        c.varStates[s.itemId] = stateIdx
+      elif vs == localRequiresLifting:
+        discard # Sym already marked
+      elif vs != stateIdx:
+        c.captureVar(s)
+  of nkReturnStmt:
+    if n[0].kind in {nkAsgn, nkFastAsgn, nkSinkAsgn}:
+      # we have a `result = result` expression produced by the closure
+      # transform, let's not touch the LHS in order to make the lifting pass
+      # correct when `result` is lifted
+      detectCapturedVars(c, n[0][1], stateIdx)
+    else:
+      detectCapturedVars(c, n[0], stateIdx)
+  else:
+    for i in 0 ..< n.safeLen:
+      detectCapturedVars(c, n[i], stateIdx)
+
+proc detectCapturedVars(c: var Ctx) =
+  for i, s in c.states:
+    detectCapturedVars(c, s.body, i)
+
+proc liftLocals(c: var Ctx, n: PNode): PNode =
+  result = n
+  case n.kind
+  of nkSym:
+    let s = n.sym
+    if c.varStates.getOrDefault(s.itemId) == localRequiresLifting:
+      # lift
+      let e = getEnvParam(c.fn)
+      let field = getFieldFromObj(e.typ.elementType, s)
+      assert(field != nil)
+      result = rawIndirectAccess(newSymNode(e), field, n.info)
+    # elif c.varStates.getOrDefault(s.itemId, localNotSeen) != localNotSeen:
+    #   echo "Not lifting ", s.name.s
+
+  of nkReturnStmt:
+    if n[0].kind in {nkAsgn, nkFastAsgn, nkSinkAsgn}:
+      # we have a `result = result` expression produced by the closure
+      # transform, let's not touch the LHS in order to make the lifting pass
+      # correct when `result` is lifted
+      n[0][1] = liftLocals(c, n[0][1])
+    else:
+      n[0] = liftLocals(c, n[0])
+  else:
+    for i in 0 ..< n.safeLen:
+      n[i] = liftLocals(c, n[i])
+
 proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n: PNode): PNode =
-  var ctx = Ctx(g: g, fn: fn, idgen: idgen)
+  var ctx = Ctx(g: g, fn: fn, idgen: idgen,
+    # should be default when issues are fixed, see #24094:
+    nimOptItersEnabled: isDefined(g.config, "nimOptIters"))
 
   if getEnvParam(fn).isNil:
-    # Lambda lifting was not done yet. Use temporary :state sym, which will
-    # be handled specially by lambda lifting. Local temp vars (if needed)
-    # should follow the same logic.
-    ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), idgen, fn, fn.info)
-    ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen)
+    if ctx.nimOptItersEnabled:
+      # The transformation should always happen after at least partial lambdalifting
+      # is performed, so that the closure iter environment is always created upfront.
+      doAssert(false, "Env param not created before iter transformation")
+    else:
+      # Lambda lifting was not done yet. Use temporary :state sym, which will
+      # be handled specially by lambda lifting. Local temp vars (if needed)
+      # should follow the same logic.
+      ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), idgen, fn, fn.info)
+      ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen)
+
   ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), idgen, fn, fn.info)
   var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen)
   var n = preprocess(pc, n.toStmtList)
@@ -1466,6 +1592,11 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
   let caseDispatcher = newTreeI(nkCaseStmt, n.info,
       ctx.newStateAccess())
 
+  if ctx.nimOptItersEnabled:
+    # Lamdalifting will not touch our locals, it is our responsibility to lift those that
+    # need it.
+    detectCapturedVars(ctx)
+
   for s in ctx.states:
     let body = ctx.transformStateAssignments(s.body)
     caseDispatcher.add newTreeI(nkOfBranch, body.info, g.newIntLit(body.info, s.label), body)
@@ -1473,6 +1604,8 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
   caseDispatcher.add newTreeI(nkElse, n.info, newTreeI(nkReturnStmt, n.info, g.emptyNode))
 
   result = wrapIntoStateLoop(ctx, caseDispatcher)
+  if ctx.nimOptItersEnabled:
+    result = liftLocals(ctx, result)
 
   when false:
     echo "TRANSFORM TO STATES: "
@@ -1481,3 +1614,5 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
     echo "exception table:"
     for i, e in ctx.exceptionTable:
       echo i, " -> ", e
+
+    echo "ENV: ", renderTree(getEnvParam(fn).typ.elementType.n)
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 176b73044..cbf915ca6 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -24,7 +24,7 @@ bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
 bootSwitch(usedGoGC, defined(gogc), "--gc:go")
 bootSwitch(usedNoGC, defined(nogc), "--gc:none")
 
-import std/[setutils, os, strutils, parseutils, parseopt, sequtils, strtabs]
+import std/[setutils, os, strutils, parseutils, parseopt, sequtils, strtabs, enumutils]
 import
   msgs, options, nversion, condsyms, extccomp, platform,
   wordrecg, nimblecmd, lineinfos, pathutils
@@ -248,6 +248,7 @@ const
   errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
   errGuiConsoleOrLibExpectedButXFound = "'gui', 'console', 'lib' or 'staticlib' expected, but '$1' found"
   errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
+  errInvalidFeatureButXFound = Feature.toSeq.map(proc(val:Feature): string = "'$1'" % $val).join(", ") & " expected, but '$1' found"
 
 template warningOptionNoop(switch: string) =
   warningDeprecated(conf, info, "'$#' is deprecated, now a noop" % switch)
@@ -303,6 +304,12 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
     else:
       result = false
       localError(conf, info, errInvalidExceptionSystem % arg)
+  of "experimental":
+    try:
+      result = conf.features.contains parseEnum[Feature](arg)
+    except ValueError:
+      result = false
+      localError(conf, info, errInvalidFeatureButXFound % arg)
   else:
     result = false
     invalidCmdLineOption(conf, passCmd1, switch, info)
@@ -462,7 +469,6 @@ proc handleCmdInput*(conf: ConfigRef) =
 proc parseCommand*(command: string): Command =
   case command.normalize
   of "c", "cc", "compile", "compiletoc": cmdCompileToC
-  of "nir": cmdCompileToNir
   of "cpp", "compiletocpp": cmdCompileToCpp
   of "objc", "compiletooc": cmdCompileToOC
   of "js", "compiletojs": cmdCompileToJS
@@ -500,7 +506,6 @@ proc setCmd*(conf: ConfigRef, cmd: Command) =
   of cmdCompileToCpp: conf.backend = backendCpp
   of cmdCompileToOC: conf.backend = backendObjc
   of cmdCompileToJS: conf.backend = backendJs
-  of cmdCompileToNir: conf.backend = backendNir
   else: discard
 
 proc setCommandEarly*(conf: ConfigRef, command: string) =
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 085576c6b..5043fc5d4 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -166,3 +166,6 @@ proc initDefines*(symbols: StringTableRef) =
   defineSymbol("nimHasWarnStdPrefix")
 
   defineSymbol("nimHasVtables")
+  defineSymbol("nimHasGenericsOpenSym2")
+  defineSymbol("nimHasGenericsOpenSym3")
+  defineSymbol("nimHasJsNoLambdaLifting")
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 8ee527952..5534d07e7 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -46,10 +46,10 @@ type
     case isTryBlock: bool
     of false:
       label: PSym
-      breakFixups: seq[(TPosition, seq[PNode])] #Contains the gotos for the breaks along with their pending finales
+      breakFixups: seq[(TPosition, seq[PNode])] # Contains the gotos for the breaks along with their pending finales
     of true:
       finale: PNode
-      raiseFixups: seq[TPosition] #Contains the gotos for the raises
+      raiseFixups: seq[TPosition] # Contains the gotos for the raises
 
   Con = object
     code: ControlFlowGraph
@@ -181,14 +181,6 @@ proc genIf(c: var Con, n: PNode) =
     goto Lend3
   L3:
     D
-    goto Lend3 # not eliminated to simplify the join generation
-  Lend3:
-    join F3
-  Lend2:
-    join F2
-  Lend:
-    join F1
-
   ]#
   var endings: seq[TPosition] = @[]
   let oldInteresting = c.interestingInstructions
@@ -213,7 +205,6 @@ proc genAndOr(c: var Con; n: PNode) =
   #   fork lab1
   #   asgn dest, b
   # lab1:
-  #   join F1
   c.gen(n[1])
   forkT:
     c.gen(n[2])
@@ -324,7 +315,7 @@ proc genRaise(c: var Con; n: PNode) =
       if c.blocks[i].isTryBlock:
         genBreakOrRaiseAux(c, i, n)
         return
-    assert false #Unreachable
+    assert false # Unreachable
   else:
     genNoReturn(c)
 
@@ -390,7 +381,6 @@ proc genCall(c: var Con; n: PNode) =
     # fork lab1
     # goto exceptionHandler (except or finally)
     # lab1:
-    # join F1
     forkT:
       for i in countdown(c.blocks.high, 0):
         if c.blocks[i].isTryBlock:
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index b4c4baa2b..8e5f5e4e7 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -831,7 +831,7 @@ proc getName(n: PNode): string =
     result = "`"
     for i in 0..<n.len: result.add(getName(n[i]))
     result = "`"
-  of nkOpenSymChoice, nkClosedSymChoice:
+  of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
     result = getName(n[0])
   else:
     result = ""
@@ -849,7 +849,7 @@ proc getNameIdent(cache: IdentCache; n: PNode): PIdent =
     var r = ""
     for i in 0..<n.len: r.add(getNameIdent(cache, n[i]).s)
     result = getIdent(cache, r)
-  of nkOpenSymChoice, nkClosedSymChoice:
+  of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
     result = getNameIdent(cache, n[0])
   else:
     result = nil
@@ -863,7 +863,7 @@ proc getRstName(n: PNode): PRstNode =
   of nkAccQuoted:
     result = getRstName(n[0])
     for i in 1..<n.len: result.text.add(getRstName(n[i]).text)
-  of nkOpenSymChoice, nkClosedSymChoice:
+  of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
     result = getRstName(n[0])
   else:
     result = nil
@@ -1206,7 +1206,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
         var param = %{"name": %($genericParam)}
         if genericParam.sym.typ.len > 0:
           param["types"] = newJArray()
-        param["types"].add %($genericParam.sym.typ.elementType)
+          param["types"] = %($genericParam.sym.typ.elementType)
         result.json["signature"]["genericParams"].add param
   if optGenIndex in d.conf.globalOptions:
     genItem(d, n, nameNode, k, kForceExport)
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index bd0875213..77c136d63 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -33,6 +33,19 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
     let x = param
     if x.kind == nkArgList:
       for y in items(x): result.add(y)
+    elif nfDefaultRefsParam in x.flags:
+      # value of default param needs to be evaluated like template body
+      # if it contains other template params
+      var res: PNode
+      if isAtom(x):
+        res = newNodeI(nkPar, x.info)
+        evalTemplateAux(x, actual, c, res)
+        if res.len == 1: res = res[0]
+      else:
+        res = copyNode(x)
+        for i in 0..<x.safeLen:
+          evalTemplateAux(x[i], actual, c, res)
+      result.add res
     else:
       result.add copyTree(x)
 
@@ -56,6 +69,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
           #  internalAssert c.config, false
           idTablePut(c.mapping, s, x)
         if sfGenSym in s.flags:
+          # TODO: getIdent(c.ic, "`" & x.name.s & "`gensym" & $c.instID)
           result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID),
             if c.instLines: actual.info else: templ.info)
         else:
diff --git a/compiler/expanddefaults.nim b/compiler/expanddefaults.nim
index c121f5dea..c520d8849 100644
--- a/compiler/expanddefaults.nim
+++ b/compiler/expanddefaults.nim
@@ -125,7 +125,7 @@ proc expandDefault(t: PType; info: TLineInfo): PNode =
   of tyString:
     result = newZero(t, info, nkStrLit)
   of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
-     tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
+     tyNil, tyGenericInvocation, tyError, tyBuiltInTypeClass,
      tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
      tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
     result = newZero(t, info, nkEmpty) # bug indicator
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 0ea458e3b..ce25da773 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -172,6 +172,22 @@ compiler vcc:
     cppXsupport: "",
     props: {hasCpp, hasAssume, hasDeclspec})
 
+# Nvidia CUDA NVCC Compiler
+compiler nvcc:
+  result = gcc()
+  result.name = "nvcc"
+  result.compilerExe = "nvcc"
+  result.cppCompiler = "nvcc"
+  result.compileTmpl = "-c -x cu -Xcompiler=\"$options\" $include -o $objfile $file"
+  result.linkTmpl = "$buildgui $builddll -o $exefile $objfiles -Xcompiler=\"$options\""
+
+# AMD HIPCC Compiler (rocm/cuda)
+compiler hipcc:
+  result = clang()
+  result.name = "hipcc"
+  result.compilerExe = "hipcc"
+  result.cppCompiler = "hipcc"
+
 compiler clangcl:
   result = vcc()
   result.name = "clang_cl"
@@ -285,7 +301,9 @@ const
     envcc(),
     icl(),
     icc(),
-    clangcl()]
+    clangcl(),
+    hipcc(),
+    nvcc()]
 
   hExt* = ".h"
 
@@ -319,7 +337,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
   var fullSuffix = suffix
   case conf.backend
   of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix
-  of backendC, backendNir: discard
+  of backendC: discard
   of backendInvalid:
     # during parsing of cfg files; we don't know the backend yet, no point in
     # guessing wrong thing
@@ -982,10 +1000,11 @@ proc jsonBuildInstructionsFile*(conf: ConfigRef): AbsoluteFile =
   # works out of the box with `hashMainCompilationParams`.
   result = getNimcacheDir(conf) / conf.outFile.changeFileExt("json")
 
-const cacheVersion = "D20210525T193831" # update when `BuildCache` spec changes
+const cacheVersion = "D20240927T193831" # update when `BuildCache` spec changes
 type BuildCache = object
   cacheVersion: string
   outputFile: string
+  outputLastModificationTime: string
   compile: seq[(string, string)]
   link: seq[string]
   linkcmd: string
@@ -1029,6 +1048,8 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
           bcache.depfiles.add (path, $secureHashFile(path))
 
     bcache.nimexe = hashNimExe()
+    if fileExists(bcache.outputFile):
+      bcache.outputLastModificationTime = $getLastModificationTime(bcache.outputFile)
   conf.jsonBuildFile = conf.jsonBuildInstructionsFile
   conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)
 
@@ -1049,6 +1070,8 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
     # xxx optimize by returning false if stdin input was the same
   for (file, hash) in bcache.depfiles:
     if $secureHashFile(file) != hash: return true
+  if bcache.outputLastModificationTime != $getLastModificationTime(bcache.outputFile):
+    return true
 
 proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
   var bcache: BuildCache = default(BuildCache)
@@ -1065,7 +1088,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
       "jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " %
       [outputCurrent, output, jsonFile.string])
   var cmds: TStringSeq = default(TStringSeq)
-  var prettyCmds: TStringSeq= default(TStringSeq)
+  var prettyCmds: TStringSeq = default(TStringSeq)
   let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
   for (name, cmd) in bcache.compile:
     cmds.add cmd
diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim
index c9f546c76..8e81633ef 100644
--- a/compiler/ic/ic.nim
+++ b/compiler/ic/ic.nim
@@ -16,7 +16,7 @@ from std/os import removeFile, isAbsolute
 
 import ../../dist/checksums/src/checksums/sha1
 
-import ".." / nir / nirlineinfos
+import iclineinfos
 
 when defined(nimPreviewSlimSystem):
   import std/[syncio, assertions, formatfloat]
@@ -59,8 +59,8 @@ type
     emittedTypeInfo*: seq[string]
     backendFlags*: set[ModuleBackendFlag]
 
-    syms*: seq[PackedSym]
-    types*: seq[PackedType]
+    syms*: OrderedTable[int32, PackedSym]
+    types*: OrderedTable[int32, PackedType]
     strings*: BiTable[string] # we could share these between modules.
     numbers*: BiTable[BiggestInt] # we also store floats in here so
                                   # that we can assure that every bit is kept
@@ -362,10 +362,10 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
   result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item)
 
   if t.uniqueId.module == c.thisModule and not c.typeMarker.containsOrIncl(t.uniqueId.item):
-    if t.uniqueId.item >= m.types.len:
-      setLen m.types, t.uniqueId.item+1
+    #if t.uniqueId.item >= m.types.len:
+    #  setLen m.types, t.uniqueId.item+1
 
-    var p = PackedType(kind: t.kind, flags: t.flags, callConv: t.callConv,
+    var p = PackedType(id: t.uniqueId.item, kind: t.kind, flags: t.flags, callConv: t.callConv,
       size: t.size, align: t.align, nonUniqueId: t.itemId.item,
       paddingAtEnd: t.paddingAtEnd)
     storeNode(p, t, n)
@@ -396,12 +396,12 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
   result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
 
   if s.itemId.module == c.thisModule and not c.symMarker.containsOrIncl(s.itemId.item):
-    if s.itemId.item >= m.syms.len:
-      setLen m.syms, s.itemId.item+1
+    #if s.itemId.item >= m.syms.len:
+    #  setLen m.syms, s.itemId.item+1
 
     assert sfForward notin s.flags
 
-    var p = PackedSym(kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
+    var p = PackedSym(id: s.itemId.item, kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
       position: s.position, offset: s.offset, disamb: s.disamb, options: s.options,
       name: s.name.s.toLitId(m))
 
@@ -414,7 +414,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
       p.bitsize = s.bitsize
       p.alignment = s.alignment
 
-    p.externalName = toLitId(s.loc.r, m)
+    p.externalName = toLitId(s.loc.snippet, m)
     p.locFlags = s.loc.flags
     c.addMissing s.typ
     p.typ = s.typ.storeType(c, m)
@@ -613,6 +613,10 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
     f.loadSection section
     f.loadSeq data
 
+  template loadTableSection(section, data) {.dirty.} =
+    f.loadSection section
+    f.loadOrderedTable data
+
   template loadTabSection(section, data) {.dirty.} =
     f.loadSection section
     f.load data
@@ -645,8 +649,8 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
     loadTabSection topLevelSection, m.topLevel
 
     loadTabSection bodiesSection, m.bodies
-    loadSeqSection symsSection, m.syms
-    loadSeqSection typesSection, m.types
+    loadTableSection symsSection, m.syms
+    loadTableSection typesSection, m.types
 
     loadSeqSection typeInstCacheSection, m.typeInstCache
     loadSeqSection procInstCacheSection, m.procInstCache
@@ -691,6 +695,10 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
     f.storeSection section
     f.store data
 
+  template storeTableSection(section, data) {.dirty.} =
+    f.storeSection section
+    f.storeOrderedTable data
+
   storeTabSection stringsSection, m.strings
 
   storeSeqSection checkSumsSection, m.includes
@@ -714,9 +722,9 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
   storeTabSection topLevelSection, m.topLevel
 
   storeTabSection bodiesSection, m.bodies
-  storeSeqSection symsSection, m.syms
+  storeTableSection symsSection, m.syms
 
-  storeSeqSection typesSection, m.types
+  storeTableSection typesSection, m.types
 
   storeSeqSection typeInstCacheSection, m.typeInstCache
   storeSeqSection procInstCacheSection, m.procInstCache
@@ -767,8 +775,8 @@ type
     status*: ModuleStatus
     symsInit, typesInit, loadedButAliveSetChanged*: bool
     fromDisk*: PackedModule
-    syms: seq[PSym] # indexed by itemId
-    types: seq[PType]
+    syms: OrderedTable[int32, PSym] # indexed by itemId
+    types: OrderedTable[int32, PType]
     module*: PSym # the one true module symbol.
     iface, ifaceHidden: Table[PIdent, seq[PackedItemId]]
       # PackedItemId so that it works with reexported symbols too
@@ -829,7 +837,7 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
     result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
   of nkSym:
     result.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree[n].soperand))
-    if result.typ == nil and nfOpenSym notin result.flags:
+    if result.typ == nil:
       result.typ = result.sym.typ
   of externIntLit:
     result.intVal = g[thisModule].fromDisk.numbers[n.litId]
@@ -843,7 +851,7 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
     assert n2.kind == nkNone
     transitionNoneToSym(result)
     result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree[n2].soperand))
-    if result.typ == nil and nfOpenSym notin result.flags:
+    if result.typ == nil:
       result.typ = result.sym.typ
   else:
     for n0 in sonsReadonly(tree, n):
@@ -937,7 +945,7 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
   result.owner = loadSym(c, g, si, s.owner)
   let externalName = g[si].fromDisk.strings[s.externalName]
   if externalName != "":
-    result.loc.r = rope externalName
+    result.loc.snippet = externalName
   result.loc.flags = s.locFlags
   result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
 
@@ -961,11 +969,11 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
         loadToReplayNodes(g, c.config, c.cache, m, g[int m])
 
     assert g[si].status in {loaded, storing, stored}
-    if not g[si].symsInit:
-      g[si].symsInit = true
-      setLen g[si].syms, g[si].fromDisk.syms.len
+    #if not g[si].symsInit:
+    #  g[si].symsInit = true
+    #  setLen g[si].syms, g[si].fromDisk.syms.len
 
-    if g[si].syms[s.item] == nil:
+    if g[si].syms.getOrDefault(s.item) == nil:
       if g[si].fromDisk.syms[s.item].kind != skModule:
         result = symHeaderFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item)
         # store it here early on, so that recursions work properly:
@@ -1012,11 +1020,11 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
     assert g[si].status in {loaded, storing, stored}
     assert t.item > 0
 
-    if not g[si].typesInit:
-      g[si].typesInit = true
-      setLen g[si].types, g[si].fromDisk.types.len
+    #if not g[si].typesInit:
+    #  g[si].typesInit = true
+    #  setLen g[si].types, g[si].fromDisk.types.len
 
-    if g[si].types[t.item] == nil:
+    if g[si].types.getOrDefault(t.item) == nil:
       result = typeHeaderFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item)
       # store it here early on, so that recursions work properly:
       g[si].types[t.item] = result
@@ -1155,10 +1163,7 @@ proc loadProcBody*(config: ConfigRef, cache: IdentCache;
 proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
                      g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
   bench g.loadType:
-    if id.item < g[module].types.len:
-      result = g[module].types[id.item]
-    else:
-      result = nil
+    result = g[module].types.getOrDefault(id.item)
     if result == nil:
       var decoder = PackedDecoder(
         lastModule: int32(-1),
@@ -1171,10 +1176,7 @@ proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
 proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
                     g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
   bench g.loadSym:
-    if id.item < g[module].syms.len:
-      result = g[module].syms[id.item]
-    else:
-      result = nil
+    result = g[module].syms.getOrDefault(id.item)
     if result == nil:
       var decoder = PackedDecoder(
         lastModule: int32(-1),
@@ -1190,19 +1192,6 @@ proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; confi
   else:
     ItemId(module: toFileIndex(id.module, g[thisModule].fromDisk, config).int32, item: id.item)
 
-proc checkForHoles(m: PackedModule; config: ConfigRef; moduleId: int) =
-  var bugs = 0
-  for i in 1 .. high(m.syms):
-    if m.syms[i].kind == skUnknown:
-      echo "EMPTY ID ", i, " module ", moduleId, " ", toFullPath(config, FileIndex(moduleId))
-      inc bugs
-  assert bugs == 0
-  when false:
-    var nones = 0
-    for i in 1 .. high(m.types):
-      inc nones, m.types[i].kind == tyNone
-    assert nones < 1
-
 proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
                            moduleSym: PSym; m: PackedModule) =
   # For now only used for heavy debugging. In the future we could use this to reduce the
diff --git a/compiler/nir/nirlineinfos.nim b/compiler/ic/iclineinfos.nim
index f11ef7c42..74a7d971b 100644
--- a/compiler/nir/nirlineinfos.nim
+++ b/compiler/ic/iclineinfos.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
+#        (c) Copyright 2024 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/compiler/ic/integrity.nim b/compiler/ic/integrity.nim
index d78e56847..3e8ea2503 100644
--- a/compiler/ic/integrity.nim
+++ b/compiler/ic/integrity.nim
@@ -10,7 +10,7 @@
 ## Integrity checking for a set of .rod files.
 ## The set must cover a complete Nim project.
 
-import std/sets
+import std/[sets, tables]
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
@@ -108,18 +108,18 @@ proc checkModule(c: var CheckedContext; m: PackedModule) =
   # We check that:
   # - Every symbol references existing types and symbols.
   # - Every tree node references existing types and symbols.
-  for i in 0..high(m.syms):
-    checkLocalSym c, int32(i)
+  for _, v in pairs(m.syms):
+    checkLocalSym c, v.id
 
   checkTree c, m.toReplay
   checkTree c, m.topLevel
 
   for e in m.exports:
-    assert e[1] >= 0 and e[1] < m.syms.len
+    #assert e[1] >= 0 and e[1] < m.syms.len
     assert e[0] == m.syms[e[1]].name
 
   for e in m.compilerProcs:
-    assert e[1] >= 0 and e[1] < m.syms.len
+    #assert e[1] >= 0 and e[1] < m.syms.len
     assert e[0] == m.syms[e[1]].name
 
   checkLocalSymIds c, m, m.converters
diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim
index da8e7e597..39037b94f 100644
--- a/compiler/ic/navigator.nim
+++ b/compiler/ic/navigator.nim
@@ -11,7 +11,7 @@
 ## IDE-like features. It uses the set of .rod files to accomplish
 ## its task. The set must cover a complete Nim project.
 
-import std/sets
+import std/[sets, tables]
 
 from std/os import nil
 from std/private/miscdollars import toLocation
@@ -20,7 +20,7 @@ when defined(nimPreviewSlimSystem):
   import std/assertions
 
 import ".." / [ast, modulegraphs, msgs, options]
-import ".." / nir / nirlineinfos
+import iclineinfos
 import packed_ast, bitabs, ic
 
 type
diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim
index 2599e07d1..a39bb7adf 100644
--- a/compiler/ic/packed_ast.nim
+++ b/compiler/ic/packed_ast.nim
@@ -16,7 +16,7 @@ import std/[hashes, tables, strtabs]
 import bitabs, rodfiles
 import ".." / [ast, options]
 
-import ".." / nir / nirlineinfos
+import iclineinfos
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
@@ -47,6 +47,7 @@ type
     path*: NodeId
 
   PackedSym* = object
+    id*: int32
     kind*: TSymKind
     name*: LitId
     typ*: PackedItemId
@@ -71,6 +72,7 @@ type
     instantiatedFrom*: PackedItemId
 
   PackedType* = object
+    id*: int32
     kind*: TTypeKind
     callConv*: TCallingConvention
     #nodekind*: TNodeKind
diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim
index 5eef3874a..ac995dd2e 100644
--- a/compiler/ic/rodfiles.nim
+++ b/compiler/ic/rodfiles.nim
@@ -19,6 +19,8 @@ from std/typetraits import supportsCopyMem
 when defined(nimPreviewSlimSystem):
   import std/[syncio, assertions]
 
+import std / tables
+
 ## Overview
 ## ========
 ## `RodFile` represents a Rod File (versioned binary format), and the
@@ -170,6 +172,18 @@ proc storeSeq*[T](f: var RodFile; s: seq[T]) =
     for i in 0..<s.len:
       storePrim(f, s[i])
 
+proc storeOrderedTable*[K, T](f: var RodFile; s: OrderedTable[K, T]) =
+  if f.err != ok: return
+  if s.len >= high(int32):
+    setError f, tooBig
+    return
+  var lenPrefix = int32(s.len)
+  if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
+    setError f, ioFailure
+  else:
+    for _, v in s:
+      storePrim(f, v)
+
 proc loadPrim*(f: var RodFile; s: var string) =
   ## Read a string, the length was stored as a prefix
   if f.err != ok: return
@@ -211,6 +225,19 @@ proc loadSeq*[T](f: var RodFile; s: var seq[T]) =
     for i in 0..<lenPrefix:
       loadPrim(f, s[i])
 
+proc loadOrderedTable*[K, T](f: var RodFile; s: var OrderedTable[K, T]) =
+  ## `T` must be compatible with `copyMem`, see `loadPrim`
+  if f.err != ok: return
+  var lenPrefix = int32(0)
+  if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
+    setError f, ioFailure
+  else:
+    s = initOrderedTable[K, T](lenPrefix)
+    for i in 0..<lenPrefix:
+      var x = default T
+      loadPrim(f, x)
+      s[x.id] = x
+
 proc storeHeader*(f: var RodFile; cookie = defaultCookie) =
   ## stores the header which is described by `cookie`.
   if f.err != ok: return
diff --git a/compiler/importer.nim b/compiler/importer.nim
index 176b33b7b..ffb7e0305 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -246,7 +246,8 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool)
     result = createModuleAliasImpl(realModule.name)
   if importHidden:
     result.options.incl optImportHidden
-  c.unusedImports.add((result, n.info))
+  let moduleIdent = if n.kind == nkInfix: n[^1] else: n
+  c.unusedImports.add((result, moduleIdent.info))
   c.importModuleMap[result.id] = realModule.id
   c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id
 
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index 6b7676653..3dcc364a3 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -317,8 +317,9 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
   ]#
   result = dest.kind != nkSym
 
-proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) =
-  if c.graph.config.selectedGC == gcOrc:
+proc finishCopy(c: var Con; result, dest: PNode; flags: set[MoveOrCopyFlag]; isFromSink: bool) =
+  if c.graph.config.selectedGC == gcOrc and IsExplicitSink notin flags:
+    # add cyclic flag, but not to sink calls, which IsExplicitSink generates
     let t = dest.typ.skipTypes(tyUserTypeClasses + {tyGenericInst, tyAlias, tySink, tyDistinct})
     if cyclicType(c.graph, t):
       result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
@@ -464,7 +465,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
       var newCall = newTreeIT(nkCall, src.info, src.typ,
             newSymNode(op),
             src)
-      c.finishCopy(newCall, n, isFromSink = true)
+      c.finishCopy(newCall, n, {}, isFromSink = true)
       result.add newTreeI(nkFastAsgn,
           src.info, tmp,
           newCall
@@ -473,7 +474,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
       result.add c.genWasMoved(tmp)
       var m = c.genCopy(tmp, n, {})
       m.add p(n, c, s, normal)
-      c.finishCopy(m, n, isFromSink = true)
+      c.finishCopy(m, n, {}, isFromSink = true)
       result.add m
     if isLValue(n) and not isCapturedVar(n) and nTyp.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
       message(c.graph.config, n.info, hintPerformance,
@@ -501,7 +502,7 @@ proc containsConstSeq(n: PNode): bool =
     return true
   result = false
   case n.kind
-  of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
+  of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkCast:
     result = containsConstSeq(n[1])
   of nkObjConstr, nkClosure:
     for i in 1..<n.len:
@@ -653,7 +654,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false,
       for j in 0 ..< it.len-1:
         branch[j] = copyTree(it[j])
       var ofScope = nestedScope(s, it.lastSon)
-      branch[^1] = if it[^1].typ.isEmptyType or willProduceStmt:
+      branch[^1] = if n.typ.isEmptyType or it[^1].typ.isEmptyType or willProduceStmt:
                      processScope(c, ofScope, maybeVoid(it[^1], ofScope))
                    else:
                      processScopeExpr(c, ofScope, it[^1], processCall, tmpFlags)
@@ -701,7 +702,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false,
         #Condition needs to be destroyed outside of the condition/branch scope
         branch[0] = p(it[0], c, s, normal)
 
-      branch[^1] = if it[^1].typ.isEmptyType or willProduceStmt:
+      branch[^1] = if n.typ.isEmptyType or it[^1].typ.isEmptyType or willProduceStmt:
                      processScope(c, branchScope, maybeVoid(it[^1], branchScope))
                    else:
                      processScopeExpr(c, branchScope, it[^1], processCall, tmpFlags)
@@ -761,7 +762,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
       let tmp = c.getTemp(s, n[0].typ, n.info)
       var m = c.genCopyNoCheck(tmp, n[0], attachedAsgn)
       m.add p(n[0], c, s, normal)
-      c.finishCopy(m, n[0], isFromSink = false)
+      c.finishCopy(m, n[0], {}, isFromSink = false)
       result = newTree(nkStmtList, c.genWasMoved(tmp), m)
       var toDisarm = n[0]
       if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
@@ -829,6 +830,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
     elif n.kind in {nkObjDownConv, nkObjUpConv}:
       result = copyTree(n)
       result[0] = p(n[0], c, s, sinkArg)
+    elif n.kind == nkCast and n.typ.skipTypes(abstractInst).kind in {tyString, tySequence}:
+      result = copyTree(n)
+      result[1] = p(n[1], c, s, sinkArg)
     elif n.typ == nil:
       # 'raise X' can be part of a 'case' expression. Deal with it here:
       result = p(n, c, s, normal)
@@ -872,7 +876,8 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
       for i in 1..<n.len:
         if n[i].kind == nkExprColonExpr:
           let field = lookupFieldAgain(t, n[i][0].sym)
-          if field != nil and sfCursor in field.flags:
+          if field != nil and (sfCursor in field.flags or field.typ.kind in {tyOpenArray, tyVarargs}):
+            # don't sink fields with openarray types
             result[i][1] = p(n[i][1], c, s, normal)
           else:
             result[i][1] = p(n[i][1], c, s, m)
@@ -893,7 +898,8 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
       elif c.inSpawn > 0:
         c.inSpawn.dec
 
-      let parameters = n[0].typ
+      # bug #23907; skips tyGenericInst for generic callbacks
+      let parameters = if n[0].typ != nil: n[0].typ.skipTypes(abstractInst) else: n[0].typ
       let L = if parameters != nil: parameters.signatureLen else: 0
 
       when false:
@@ -1168,7 +1174,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
         result = c.genCopy(dest, ri, flags)
         dec c.inEnsureMove, isEnsureMove
         result.add p(ri, c, s, consumed)
-        c.finishCopy(result, dest, isFromSink = false)
+        c.finishCopy(result, dest, flags, isFromSink = false)
     of nkBracket:
       # array constructor
       if ri.len > 0 and isDangerousSeq(ri.typ):
@@ -1176,7 +1182,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
         result = c.genCopy(dest, ri, flags)
         dec c.inEnsureMove, isEnsureMove
         result.add p(ri, c, s, consumed)
-        c.finishCopy(result, dest, isFromSink = false)
+        c.finishCopy(result, dest, flags, isFromSink = false)
       else:
         result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
     of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
@@ -1186,9 +1192,9 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
         # Rule 3: `=sink`(x, z); wasMoved(z)
         let snk = c.genSink(s, dest, ri, flags)
         result = newTree(nkStmtList, snk, c.genWasMoved(ri))
-      elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
-          isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri) and
-          not ({sfGlobal, sfPure} <= ri.sym.flags):
+      elif ri.sym.kind != skParam and
+          isAnalysableFieldAccess(ri, c.owner) and
+          isLastRead(ri, c, s) and canBeMoved(c, dest.typ):
         # Rule 3: `=sink`(x, z); wasMoved(z)
         let snk = c.genSink(s, dest, ri, flags)
         result = newTree(nkStmtList, snk, c.genWasMoved(ri))
@@ -1197,7 +1203,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
         result = c.genCopy(dest, ri, flags)
         dec c.inEnsureMove, isEnsureMove
         result.add p(ri, c, s, consumed)
-        c.finishCopy(result, dest, isFromSink = false)
+        c.finishCopy(result, dest, flags, isFromSink = false)
     of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast:
       result = c.genSink(s, dest, p(ri, c, s, sinkArg), flags)
     of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
@@ -1217,7 +1223,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
         result = c.genCopy(dest, ri, flags)
         dec c.inEnsureMove, isEnsureMove
         result.add p(ri, c, s, consumed)
-        c.finishCopy(result, dest, isFromSink = false)
+        c.finishCopy(result, dest, flags, isFromSink = false)
 
 when false:
   proc computeUninit(c: var Con) =
diff --git a/compiler/installer.ini b/compiler/installer.ini
index 8569d0ef8..54a35dbee 100644
--- a/compiler/installer.ini
+++ b/compiler/installer.ini
@@ -6,11 +6,11 @@ Name: "Nim"
 Version: "$version"
 Platforms: """
   windows: i386;amd64
-  linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64
+  linux: i386;hppa;ia64;alpha;amd64;powerpc64;arm;sparc;sparc64;m68k;mips;mipsel;mips64;mips64el;powerpc;powerpc64el;arm64;riscv32;riscv64;loongarch64
   macosx: i386;amd64;powerpc64;arm64
   solaris: i386;amd64;sparc;sparc64
   freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el
-  netbsd: i386;amd64
+  netbsd: i386;amd64;arm64
   openbsd: i386;amd64;arm;arm64
   dragonfly: i386;amd64
   crossos: amd64
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index baebfe188..713944def 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -33,7 +33,7 @@ import
   nversion, msgs, idents, types,
   ropes, wordrecg, renderer,
   cgmeth, lowerings, sighashes, modulegraphs, lineinfos,
-  transf, injectdestructors, sourcemap, astmsgs, backendpragmas,
+  transf, injectdestructors, sourcemap, astmsgs, pushpoppragmas,
   mangleutils
 
 import pipelineutils
@@ -103,7 +103,7 @@ type
     prc: PSym
     globals, locals, body: Rope
     options: TOptions
-    optionsStack: seq[TOptions]
+    optionsStack: seq[(TOptions, TNoteKinds)]
     module: BModule
     g: PGlobals
     beforeRetNeeded: bool
@@ -111,13 +111,25 @@ type
     blocks: seq[TBlock]
     extraIndent: int
     previousFileName: string  # For frameInfo inside templates.
+    # legacy: generatedParamCopies and up fields are used for jsNoLambdaLifting
+    generatedParamCopies: IntSet
+    up: PProc     # up the call chain; required for closure support
 
 template config*(p: PProc): ConfigRef = p.module.config
 
 proc indentLine(p: PProc, r: Rope): Rope =
   var p = p
-  let ind = p.blocks.len + p.extraIndent
-  result = repeat(' ', ind*2) & r
+  if jsNoLambdaLifting in p.config.legacyFeatures:
+    var ind = 0
+    while true:
+      inc ind, p.blocks.len + p.extraIndent
+      if p.up == nil or p.up.prc != p.prc.owner:
+        break
+      p = p.up
+    result = repeat(' ', ind*2) & r
+  else:
+    let ind = p.blocks.len + p.extraIndent
+    result = repeat(' ', ind*2) & r
 
 template line(p: PProc, added: string) =
   p.body.add(indentLine(p, rope(added)))
@@ -183,7 +195,7 @@ proc mapType(typ: PType): TJSTypeKind =
   of tyPointer:
     # treat a tyPointer like a typed pointer to an array of bytes
     result = etyBaseIndex
-  of tyRange, tyDistinct, tyOrdinal, tyProxy, tyLent:
+  of tyRange, tyDistinct, tyOrdinal, tyError, tyLent:
     # tyLent is no-op as JS has pass-by-reference semantics
     result = mapType(skipModifier t)
   of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
@@ -234,7 +246,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
     for chr in name:
       if chr notin {'A'..'Z','a'..'z','_','$','0'..'9'}:
         return false
-  result = s.loc.r
+  result = s.loc.snippet
   if result == "":
     if s.kind == skField and s.name.s.validJsName:
       result = rope(s.name.s)
@@ -265,7 +277,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
       else:
         result.add("_")
         result.add(rope(s.id))
-    s.loc.r = result
+    s.loc.snippet = result
 
 proc escapeJSString(s: string): string =
   result = newStringOfCap(s.len + s.len shr 2)
@@ -599,6 +611,17 @@ template unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   r.res = frmt % [a, tmp]
   r.kind = resExpr
 
+proc genBreakState(p: PProc, n: PNode, r: var TCompRes) =
+  var a: TCompRes = default(TCompRes)
+  # mangle `:state` properly somehow
+  if n.kind == nkClosure:
+    gen(p, n[1], a)
+    r.res = "(($1).HEX3Astate < 0)" % [rdLoc(a)]
+  else:
+    gen(p, n, a)
+    r.res = "((($1.ClE_0).HEX3Astate) < 0)" % [rdLoc(a)]
+  r.kind = resExpr
+
 proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
   var
     x, y: TCompRes = default(TCompRes)
@@ -969,7 +992,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
         # if isJsObject(throwObj.typ):
         if isImportedException(throwObj.typ, p.config):
           orExpr.addf("lastJSError instanceof $1",
-            [throwObj.typ.sym.loc.r])
+            [throwObj.typ.sym.loc.snippet])
         else:
           orExpr.addf("isObj(lastJSError.m_type, $1)",
                [genTypeInfo(p, throwObj.typ)])
@@ -979,8 +1002,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
       # If some branch requires a local alias introduce it here. This is needed
       # since JS cannot do ``catch x as y``.
       if excAlias != nil:
-        excAlias.sym.loc.r = mangleName(p.module, excAlias.sym)
-        lineF(p, "var $1 = lastJSError;$n", excAlias.sym.loc.r)
+        excAlias.sym.loc.snippet = mangleName(p.module, excAlias.sym)
+        lineF(p, "var $1 = lastJSError;$n", excAlias.sym.loc.snippet)
       gen(p, n[i][^1], a)
       moveInto(p, a, r)
       lineF(p, "}$n", [])
@@ -1086,14 +1109,19 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
           lineF(p, "break;$n", [])
     of nkElse:
       if transferRange:
-         lineF(p, "else{$n", [])
+        if n.len == 2: # a dangling else for a case statement
+          transferRange = false
+          lineF(p, "switch ($1) {$n", [cond.rdLoc])
+          lineF(p, "default: $n", [])
+        else:
+          lineF(p, "else{$n", [])
       else:
         lineF(p, "default: $n", [])
       p.nested:
         gen(p, it[0], stmt)
         moveInto(p, stmt, r)
         if transferRange:
-           lineF(p, "}$n", [])
+          lineF(p, "}$n", [])
         else:
           lineF(p, "break;$n", [])
     else: internalError(p.config, it.info, "jsgen.genCaseStmt")
@@ -1200,12 +1228,13 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
 proc generateHeader(p: PProc, prc: PSym): Rope =
   result = ""
   let typ = prc.typ
-  if typ.callConv == ccClosure:
-    # we treat Env as the `this` parameter of the function
-    # to keep it simple
-    let env = prc.ast[paramsPos].lastSon
-    assert env.kind == nkSym, "env is missing"
-    env.sym.loc.r = "this"
+  if jsNoLambdaLifting notin p.config.legacyFeatures:
+    if typ.callConv == ccClosure:
+      # we treat Env as the `this` parameter of the function
+      # to keep it simple
+      let env = prc.ast[paramsPos].lastSon
+      assert env.kind == nkSym, "env is missing"
+      env.sym.loc.snippet = "this"
 
   for i in 1..<typ.n.len:
     assert(typ.n[i].kind == nkSym)
@@ -1239,9 +1268,10 @@ const
 
 proc needsNoCopy(p: PProc; y: PNode): bool =
   return y.kind in nodeKindsNeedNoCopy or
-        ((mapType(y.typ) != etyBaseIndex) and
+        ((mapType(y.typ) != etyBaseIndex or
+          (jsNoLambdaLifting in p.config.legacyFeatures and y.kind == nkSym and y.sym.kind == skParam)) and
           (skipTypes(y.typ, abstractInst).kind in
-            {tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned} + IntegralTypes))
+            {tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned, tyOpenArray} + IntegralTypes))
 
 proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
   var a, b: TCompRes = default(TCompRes)
@@ -1268,7 +1298,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
       lineF(p, "$1 = nimCopy(null, $2, $3);$n",
                [a.rdLoc, b.res, genTypeInfo(p, y.typ)])
   of etyObject:
-    if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
+    if x.typ.kind in {tyVar, tyLent, tyOpenArray, tyVarargs} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
       lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
     else:
       useMagic(p, "nimCopy")
@@ -1346,8 +1376,8 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
   else:
     if b[1].kind != nkSym: internalError(p.config, b[1].info, "genFieldAddr")
     var f = b[1].sym
-    if f.loc.r == "": f.loc.r = mangleName(p.module, f)
-    r.res = makeJSString($f.loc.r)
+    if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
+    r.res = makeJSString($f.loc.snippet)
   internalAssert p.config, a.typ != etyBaseIndex
   r.address = a.res
   r.kind = resExpr
@@ -1374,8 +1404,8 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
   else:
     if n[1].kind != nkSym: internalError(p.config, n[1].info, "genFieldAccess")
     var f = n[1].sym
-    if f.loc.r == "": f.loc.r = mangleName(p.module, f)
-    r.res = "$1.$2" % [r.res, f.loc.r]
+    if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
+    r.res = "$1.$2" % [r.res, f.loc.snippet]
     mkTemp(1)
   r.kind = resExpr
 
@@ -1395,11 +1425,11 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
   # Field symbol
   var field = accessExpr[1].sym
   internalAssert p.config, field.kind == skField
-  if field.loc.r == "": field.loc.r = mangleName(p.module, field)
+  if field.loc.snippet == "": field.loc.snippet = mangleName(p.module, field)
   # Discriminant symbol
   let disc = checkExpr[2].sym
   internalAssert p.config, disc.kind == skField
-  if disc.loc.r == "": disc.loc.r = mangleName(p.module, disc)
+  if disc.loc.snippet == "": disc.loc.snippet = mangleName(p.module, disc)
 
   var setx: TCompRes = default(TCompRes)
   gen(p, checkExpr[1], setx)
@@ -1416,16 +1446,16 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
   useMagic(p, "reprDiscriminant") # no need to offset by firstOrd unlike for cgen
   let msg = genFieldDefect(p.config, field.name.s, disc)
   lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError2(makeNimstrLit($5), reprDiscriminant($2.$3, $6)); }$n",
-    setx.res, tmp, disc.loc.r, if negCheck: "!==" else: "===",
+    setx.res, tmp, disc.loc.snippet, if negCheck: "!==" else: "===",
     makeJSString(msg), genTypeInfo(p, disc.typ))
 
   if addrTyp != nil and mapType(p, addrTyp) == etyBaseIndex:
     r.typ = etyBaseIndex
-    r.res = makeJSString($field.loc.r)
+    r.res = makeJSString($field.loc.snippet)
     r.address = tmp
   else:
     r.typ = etyNone
-    r.res = "$1.$2" % [tmp, field.loc.r]
+    r.res = "$1.$2" % [tmp, field.loc.snippet]
   r.kind = resExpr
 
 proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
@@ -1456,7 +1486,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
   r.kind = resExpr
 
 proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
-  var ty = skipTypes(n[0].typ, abstractVarRange)
+  var ty = skipTypes(n[0].typ, abstractVarRange+tyUserTypeClasses)
   if ty.kind in {tyRef, tyPtr, tyLent, tyOwned}: ty = skipTypes(ty.elementType, abstractVarRange)
   case ty.kind
   of tyArray, tyOpenArray, tySequence, tyString, tyCstring, tyVarargs:
@@ -1492,10 +1522,10 @@ template isIndirect(x: PSym): bool =
 
 proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
   let s = n.sym
-  if s.loc.r == "": internalError(p.config, n.info, "genAddr: 3")
+  if s.loc.snippet == "": internalError(p.config, n.info, "genAddr: 3")
   case s.kind
   of skParam:
-    r.res = s.loc.r
+    r.res = s.loc.snippet
     r.address = ""
     r.typ = etyNone
   of skVar, skLet, skResult:
@@ -1509,15 +1539,15 @@ proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
       # make addr() a no-op:
       r.typ = etyNone
       if isIndirect(s):
-        r.res = s.loc.r & "[0]"
+        r.res = s.loc.snippet & "[0]"
       else:
-        r.res = s.loc.r
+        r.res = s.loc.snippet
       r.address = ""
     elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
       # for ease of code generation, we do not distinguish between
       # sfAddrTaken and sfGlobal.
       r.typ = etyBaseIndex
-      r.address = s.loc.r
+      r.address = s.loc.snippet
       r.res = rope("0")
     else:
       # 'var openArray' for instance produces an 'addr' but this is harmless:
@@ -1590,7 +1620,30 @@ proc attachProc(p: PProc; s: PSym) =
 
 proc genProcForSymIfNeeded(p: PProc, s: PSym) =
   if not p.g.generatedSyms.containsOrIncl(s.id):
-    attachProc(p, s)
+    if jsNoLambdaLifting in p.config.legacyFeatures:
+      let newp = genProc(p, s)
+      var owner = p
+      while owner != nil and owner.prc != s.owner:
+        owner = owner.up
+      if owner != nil: owner.locals.add(newp)
+      else: attachProc(p, newp, s)
+    else:
+      attachProc(p, s)
+
+proc genCopyForParamIfNeeded(p: PProc, n: PNode) =
+  let s = n.sym
+  if p.prc == s.owner or needsNoCopy(p, n):
+    return
+  var owner = p.up
+  while true:
+    if owner == nil:
+      internalError(p.config, n.info, "couldn't find the owner proc of the closed over param: " & s.name.s)
+    if owner.prc == s.owner:
+      if not owner.generatedParamCopies.containsOrIncl(s.id):
+        let copy = "$1 = nimCopy(null, $1, $2);$n" % [s.loc.snippet, genTypeInfo(p, s.typ)]
+        owner.locals.add(owner.indentLine(copy))
+      return
+    owner = owner.up
 
 proc genVarInit(p: PProc, v: PSym, n: PNode)
 
@@ -1598,38 +1651,40 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
   var s = n.sym
   case s.kind
   of skVar, skLet, skParam, skTemp, skResult, skForVar:
-    if s.loc.r == "":
+    if s.loc.snippet == "":
       internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
     if sfCompileTime in s.flags:
       genVarInit(p, s, if s.astdef != nil: s.astdef else: newNodeI(nkEmpty, s.info))
+    if jsNoLambdaLifting in p.config.legacyFeatures and s.kind == skParam:
+      genCopyForParamIfNeeded(p, n)
     let k = mapType(p, s.typ)
     if k == etyBaseIndex:
       r.typ = etyBaseIndex
       if {sfAddrTaken, sfGlobal} * s.flags != {}:
         if isIndirect(s):
-          r.address = "$1[0][0]" % [s.loc.r]
-          r.res = "$1[0][1]" % [s.loc.r]
+          r.address = "$1[0][0]" % [s.loc.snippet]
+          r.res = "$1[0][1]" % [s.loc.snippet]
         else:
-          r.address = "$1[0]" % [s.loc.r]
-          r.res = "$1[1]" % [s.loc.r]
+          r.address = "$1[0]" % [s.loc.snippet]
+          r.res = "$1[1]" % [s.loc.snippet]
       else:
-        r.address = s.loc.r
-        r.res = s.loc.r & "_Idx"
+        r.address = s.loc.snippet
+        r.res = s.loc.snippet & "_Idx"
     elif isIndirect(s):
-      r.res = "$1[0]" % [s.loc.r]
+      r.res = "$1[0]" % [s.loc.snippet]
     else:
-      r.res = s.loc.r
+      r.res = s.loc.snippet
   of skConst:
     genConstant(p, s)
-    if s.loc.r == "":
+    if s.loc.snippet == "":
       internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
-    r.res = s.loc.r
+    r.res = s.loc.snippet
   of skProc, skFunc, skConverter, skMethod, skIterator:
     if sfCompileTime in s.flags:
       localError(p.config, n.info, "request to generate code for .compileTime proc: " &
           s.name.s)
     discard mangleName(p.module, s)
-    r.res = s.loc.r
+    r.res = s.loc.snippet
     if lfNoDecl in s.loc.flags or s.magic notin generatedMagics or
        {sfImportc, sfInfixCall} * s.flags != {}:
       discard
@@ -1641,13 +1696,13 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
     else:
       genProcForSymIfNeeded(p, s)
   else:
-    if s.loc.r == "":
+    if s.loc.snippet == "":
       internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
     if mapType(p, s.typ) == etyBaseIndex:
-      r.address = s.loc.r
-      r.res = s.loc.r & "_Idx"
+      r.address = s.loc.snippet
+      r.res = s.loc.snippet & "_Idx"
     else:
-      r.res = s.loc.r
+      r.res = s.loc.snippet
   r.kind = resVal
 
 proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
@@ -1789,9 +1844,9 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
 proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
   # don't call '$' here for efficiency:
   let f = n[0].sym
-  if f.loc.r == "": f.loc.r = mangleName(p.module, f)
+  if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
   if sfInfixCall in f.flags:
-    let pat = $n[0].sym.loc.r
+    let pat = $n[0].sym.loc.snippet
     internalAssert p.config, pat.len > 0
     if pat.contains({'#', '(', '@'}):
       var typ = skipTypes(n[0].typ, abstractInst)
@@ -1906,7 +1961,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
   of tyInt8..tyInt32, tyUInt8..tyUInt32, tyEnum, tyChar:
     result = putToSeq("0", indirect)
   of tyInt, tyUInt:
-    if $t.sym.loc.r == "bigint":
+    if $t.sym.loc.snippet == "bigint":
       result = putToSeq("0n", indirect)
     else:
       result = putToSeq("0", indirect)
@@ -1966,7 +2021,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
       result = putToSeq("null", indirect)
   of tySequence, tyString:
     result = putToSeq("[]", indirect)
-  of tyCstring, tyProc:
+  of tyCstring, tyProc, tyOpenArray:
     result = putToSeq("null", indirect)
   of tyStatic:
     if t.n != nil:
@@ -2018,7 +2073,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
     gen(p, n, a)
     case mapType(p, v.typ)
     of etyObject, etySeq:
-      if needsNoCopy(p, n):
+      if v.typ.kind in {tyOpenArray, tyVarargs} or needsNoCopy(p, n):
         s = a.res
       else:
         useMagic(p, "nimCopy")
@@ -2028,28 +2083,28 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
       if a.typ == etyBaseIndex:
         if targetBaseIndex:
           line(p, runtimeFormat(varCode & " = $3, $2_Idx = $4;$n",
-                   [returnType, v.loc.r, a.address, a.res]))
+                   [returnType, v.loc.snippet, a.address, a.res]))
         else:
           if isIndirect(v):
             line(p, runtimeFormat(varCode & " = [[$3, $4]];$n",
-                     [returnType, v.loc.r, a.address, a.res]))
+                     [returnType, v.loc.snippet, a.address, a.res]))
           else:
             line(p, runtimeFormat(varCode & " = [$3, $4];$n",
-                     [returnType, v.loc.r, a.address, a.res]))
+                     [returnType, v.loc.snippet, a.address, a.res]))
       else:
         if targetBaseIndex:
           let tmp = p.getTemp
           lineF(p, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
-                   [tmp, a.res, v.loc.r])
+                   [tmp, a.res, v.loc.snippet])
         else:
-          line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.r, a.res]))
+          line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.snippet, a.res]))
       return
     else:
       s = a.res
     if isIndirect(v):
-      line(p, runtimeFormat(varCode & " = [$3];$n", [returnType, v.loc.r, s]))
+      line(p, runtimeFormat(varCode & " = [$3];$n", [returnType, v.loc.snippet, s]))
     else:
-      line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.r, s]))
+      line(p, runtimeFormat(varCode & " = $3;$n", [returnType, v.loc.snippet, s]))
 
   if useReloadingGuard or useGlobalPragmas:
     dec p.extraIndent
@@ -2212,16 +2267,17 @@ proc genDefault(p: PProc, n: PNode; r: var TCompRes) =
   r.res = createVar(p, n.typ, indirect = false)
   r.kind = resExpr
 
-proc genReset(p: PProc, n: PNode) =
+proc genWasMoved(p: PProc, n: PNode) =
+  # TODO: it should be done by nir
   var x: TCompRes = default(TCompRes)
-  useMagic(p, "genericReset")
   gen(p, n[1], x)
   if x.typ == etyBaseIndex:
     lineF(p, "$1 = null, $2 = 0;$n", [x.address, x.res])
   else:
-    let (a, tmp) = maybeMakeTempAssignable(p, n[1], x)
-    lineF(p, "$1 = genericReset($3, $2);$n", [a,
-                  genTypeInfo(p, n[1].typ), tmp])
+    var y: TCompRes = default(TCompRes)
+    genDefault(p, n[1], y)
+    let (a, _) = maybeMakeTempAssignable(p, n[1], x)
+    lineF(p, "$1 = $2;$n", [a, y.rdLoc])
 
 proc genMove(p: PProc; n: PNode; r: var TCompRes) =
   var a: TCompRes = default(TCompRes)
@@ -2229,7 +2285,7 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) =
   r.res = p.getTemp()
   gen(p, n[1], a)
   lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc])
-  genReset(p, n)
+  genWasMoved(p, n)
   #lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
 
 proc genDup(p: PProc; n: PNode; r: var TCompRes) =
@@ -2410,7 +2466,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]")
   of mOf: genOf(p, n, r)
   of mDefault, mZeroDefault: genDefault(p, n, r)
-  of mReset, mWasMoved: genReset(p, n)
+  of mWasMoved: genWasMoved(p, n)
   of mEcho: genEcho(p, n, r)
   of mNLen..mNError, mSlurp, mStaticExec:
     localError(p.config, n.info, errXMustBeCompileTime % n[0].sym.name.s)
@@ -2523,17 +2579,17 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
     let val = it[1]
     gen(p, val, a)
     var f = it[0].sym
-    if f.loc.r == "": f.loc.r = mangleName(p.module, f)
+    if f.loc.snippet == "": f.loc.snippet = mangleName(p.module, f)
     fieldIDs.incl(lookupFieldAgain(n.typ.skipTypes({tyDistinct}), f).id)
 
     let typ = val.typ.skipTypes(abstractInst)
     if a.typ == etyBaseIndex:
-      initList.addf("$#: [$#, $#]", [f.loc.r, a.address, a.res])
+      initList.addf("$#: [$#, $#]", [f.loc.snippet, a.address, a.res])
     else:
       if not needsNoCopy(p, val):
         useMagic(p, "nimCopy")
         a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
-      initList.addf("$#: $#", [f.loc.r, a.res])
+      initList.addf("$#: $#", [f.loc.snippet, a.res])
   let t = skipTypes(n.typ, abstractInst + skipPtrs)
   createObjInitList(p, t, fieldIDs, initList)
   r.res = ("{$1}") % [initList]
@@ -2592,7 +2648,13 @@ proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
   let src = skipTypes(n[0].typ, abstractVarRange)
   let dest = skipTypes(n.typ, abstractVarRange)
   if optRangeCheck notin p.options:
-    return
+    if optJsBigInt64 in p.config.globalOptions and
+          dest.kind in {tyUInt..tyUInt32, tyInt..tyInt32} and
+          src.kind in {tyInt64, tyUInt64}:
+      # conversions to Number are kept
+      r.res = "Number($1)" % [r.res]
+    else:
+      discard
   elif dest.kind in {tyUInt..tyUInt64} and checkUnsignedConversions notin p.config.legacyFeatures:
     if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
       r.res = "BigInt.asUintN($1, $2)" % [$(dest.size * 8), r.res]
@@ -2687,6 +2749,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
   #if gVerbosity >= 3:
   #  echo "BEGIN generating code for: " & prc.name.s
   var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
+  p.up = oldProc
   var returnStmt: Rope = ""
   var resultAsgn: Rope = ""
   var name = mangleName(p.module, prc)
@@ -2772,9 +2835,9 @@ proc genPragma(p: PProc, n: PNode) =
     case whichPragma(it)
     of wEmit: genAsmOrEmitStmt(p, it[1])
     of wPush:
-      processPushBackendOption(p.optionsStack, p.options, n, i+1)
+      processPushBackendOption(p.config, p.optionsStack, p.options, n, i+1)
     of wPop:
-      processPopBackendOption(p.optionsStack, p.options)
+      processPopBackendOption(p.config, p.optionsStack, p.options)
     else: discard
 
 proc genCast(p: PProc, n: PNode, r: var TCompRes) =
@@ -2910,14 +2973,17 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
     else:
       genCall(p, n, r)
   of nkClosure:
-    let tmp = getTemp(p)
-    var a: TCompRes = default(TCompRes)
-    var b: TCompRes = default(TCompRes)
-    gen(p, n[0], a)
-    gen(p, n[1], b)
-    lineF(p, "$1 = $2.bind($3); $1.ClP_0 = $2; $1.ClE_0 = $3;$n", [tmp, a.rdLoc, b.rdLoc])
-    r.res = tmp
-    r.kind = resVal
+    if jsNoLambdaLifting in p.config.legacyFeatures:
+      gen(p, n[0], r)
+    else:
+      let tmp = getTemp(p)
+      var a: TCompRes = default(TCompRes)
+      var b: TCompRes = default(TCompRes)
+      gen(p, n[0], a)
+      gen(p, n[1], b)
+      lineF(p, "$1 = $2.bind($3); $1.ClP_0 = $2; $1.ClE_0 = $3;$n", [tmp, a.rdLoc, b.rdLoc])
+      r.res = tmp
+      r.kind = resVal
   of nkCurly: genSetConstr(p, n, r)
   of nkBracket: genArrayConstr(p, n, r)
   of nkPar, nkTupleConstr: genTupleConstr(p, n, r)
@@ -2948,7 +3014,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkLambdaKinds:
     let s = n[namePos].sym
     discard mangleName(p.module, s)
-    r.res = s.loc.r
+    r.res = s.loc.snippet
     if lfNoDecl in s.loc.flags or s.magic notin generatedMagics: discard
     elif not p.g.generatedSyms.containsOrIncl(s.id):
       p.locals.add(genProc(p, s))
@@ -2999,16 +3065,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkGotoState, nkState:
     globalError(p.config, n.info, "not implemented")
   of nkBreakState:
-    var a: TCompRes = default(TCompRes)
-    if n[0].kind == nkClosure:
-      gen(p, n[0][1], a)
-      let sym = n[0][1].typ[0].n[0].sym
-      r.res = "(($1).$2 < 0)" % [rdLoc(a), mangleName(p.module, sym)]
-    else:
-      gen(p, n[0], a)
-      let sym = n[0].typ[0].n[0].sym
-      r.res = "((($1.ClE_0).$2) < 0)" % [rdLoc(a), mangleName(p.module, sym)]
-    r.kind = resExpr
+    genBreakState(p, n[0], r)
   of nkPragmaBlock: gen(p, n.lastSon, r)
   of nkComesFrom:
     discard "XXX to implement for better stack traces"
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index c32a1c614..54cdfc5bc 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -145,11 +145,13 @@ proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
   result = newSym(skField, getIdent(g.cache, ":state"), idgen, iter, iter.info)
   result.typ = createClosureIterStateType(g, iter, idgen)
 
+template isIterator*(owner: PSym): bool =
+  owner.kind == skIterator and owner.typ.callConv == ccClosure
+
 proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType =
-  # YYY meh, just add the state field for every closure for now, it's too
-  # hard to figure out if it comes from a closure iterator:
   result = createObj(g, idgen, owner, info, final=false)
-  rawAddField(result, createStateField(g, owner, idgen))
+  if owner.isIterator or not isDefined(g.config, "nimOptIters"):
+    rawAddField(result, createStateField(g, owner, idgen))
 
 proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
   if resultPos < iter.ast.len:
@@ -172,26 +174,22 @@ proc addHiddenParam(routine: PSym, param: PSym) =
   assert sfFromGeneric in param.flags
   #echo "produced environment: ", param.id, " for ", routine.id
 
-proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym =
+proc getEnvParam*(routine: PSym): PSym =
   let params = routine.ast[paramsPos]
   let hidden = lastSon(params)
   if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName:
     result = hidden.sym
     assert sfFromGeneric in result.flags
   else:
+    result = nil
+
+proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym =
+  result = getEnvParam(routine)
+  if result.isNil:
     # writeStackTrace()
     localError(g.config, routine.info, "internal error: could not find env param for " & routine.name.s)
     result = routine
 
-proc getEnvParam*(routine: PSym): PSym =
-  let params = routine.ast[paramsPos]
-  let hidden = lastSon(params)
-  if hidden.kind == nkSym and hidden.sym.name.s == paramName:
-    result = hidden.sym
-    assert sfFromGeneric in result.flags
-  else:
-    result = nil
-
 proc interestingVar(s: PSym): bool {.inline.} =
   result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
     sfGlobal notin s.flags and
@@ -231,13 +229,16 @@ proc makeClosure*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; env: PNode; inf
     prc.flags.incl sfInjectDestructors
 
 proc interestingIterVar(s: PSym): bool {.inline.} =
+  # unused with -d:nimOptIters
   # XXX optimization: Only lift the variable if it lives across
   # yield/return boundaries! This can potentially speed up
   # closure iterators quite a bit.
   result = s.kind in {skResult, skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
 
-template isIterator*(owner: PSym): bool =
-  owner.kind == skIterator and owner.typ.callConv == ccClosure
+template liftingHarmful(conf: ConfigRef; owner: PSym): bool =
+  ## lambda lifting can be harmful for JS-like code generators.
+  let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
+  jsNoLambdaLifting in conf.legacyFeatures and conf.backend == backendJs and not isCompileTime
 
 proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen: IdGenerator; owner: PSym) =
   if owner.kind != skMacro:
@@ -255,11 +256,11 @@ proc genCreateEnv(env: PNode): PNode =
 
 proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
   # transforms  (iter)  to  (let env = newClosure[iter](); (iter, env))
+  if liftingHarmful(g.config, owner): return n
   let iter = n.sym
   assert iter.isIterator
 
-  result = newNodeIT(nkStmtListExpr, n.info, n.typ)
-
+  result = newNodeIT(nkStmtListExpr, n.info, iter.typ)
   let hp = getHiddenParam(g, iter)
   var env: PNode
   if owner.isIterator:
@@ -281,6 +282,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
   result.add makeClosure(g, idgen, iter, env, n.info)
 
 proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner: PSym): PNode =
+  # unused with -d:nimOptIters
   let envParam = getHiddenParam(g, owner)
   let obj = envParam.typ.skipTypes({tyOwned, tyRef, tyPtr})
   let field = addField(obj, s, g.cache, idgen)
@@ -298,8 +300,8 @@ proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
     localError(g.config, n.info,
       ("'$1' is of type <$2> which cannot be captured as it would violate memory" &
        " safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." &
-       " Consider using a <ref $2> which can be captured.") %
-      [s.name.s, typeToString(s.typ), g.config$s.info])
+       " Consider using a <ref T> which can be captured.") %
+      [s.name.s, typeToString(s.typ.skipTypes({tyVar})), g.config$s.info])
   elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv):
     localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
       [s.name.s, owner.name.s, $owner.typ.callConv])
@@ -336,9 +338,13 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
                         info: TLineInfo): PType =
   result = c.ownerToType.getOrDefault(owner.id)
   if result.isNil:
-    result = newType(tyRef, c.idgen, owner)
-    let obj = createEnvObj(c.graph, c.idgen, owner, info)
-    rawAddSon(result, obj)
+    let env = getEnvParam(owner)
+    if env.isNil or not owner.isIterator or not isDefined(c.graph.config, "nimOptIters"):
+      result = newType(tyRef, c.idgen, owner)
+      let obj = createEnvObj(c.graph, c.idgen, owner, info)
+      rawAddSon(result, obj)
+    else:
+      result = env.typ
     c.ownerToType[owner.id] = result
 
 proc asOwnedRef(c: var DetectionPass; t: PType): PType =
@@ -454,7 +460,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
       if owner.isIterator:
         c.somethingToDo = true
         addClosureParam(c, owner, n.info)
-        if interestingIterVar(s):
+        if not isDefined(c.graph.config, "nimOptIters") and interestingIterVar(s):
           if not c.capturedVars.contains(s.id):
             if not c.inTypeOf: c.capturedVars.incl(s.id)
             let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
@@ -768,7 +774,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
     elif s.id in d.capturedVars:
       if s.owner != owner:
         result = accessViaEnvParam(d.graph, n, owner)
-      elif owner.isIterator and interestingIterVar(s):
+      elif owner.isIterator and not isDefined(d.graph.config, "nimOptIters") and interestingIterVar(s):
         result = accessViaEnvParam(d.graph, n, owner)
       else:
         result = accessViaEnvVar(n, owner, d, c)
@@ -880,12 +886,16 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
                   idgen: IdGenerator; flags: TransformFlags): PNode =
   let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
 
-  if body.kind == nkEmpty or
+  if body.kind == nkEmpty or (jsNoLambdaLifting in g.config.legacyFeatures and
+      g.config.backend == backendJs and not isCompileTime) or
       (fn.skipGenericOwner.kind != skModule and force notin flags):
 
     # ignore forward declaration:
     result = body
     tooEarly = true
+    if fn.isIterator and isDefined(g.config, "nimOptIters"):
+      var d = initDetectionPass(g, fn, idgen)
+      addClosureParam(d, fn, body.info)
   else:
     var d = initDetectionPass(g, fn, idgen)
     detectCapturedVars(body, fn, d)
@@ -940,6 +950,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
           break
         ...
     """
+  if liftingHarmful(g.config, owner): return body
   if not (body.kind == nkForStmt and body[^2].kind in nkCallKinds):
     localError(g.config, body.info, "ignored invalid for loop")
     return body
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index 350b4cc25..9ff5c0a9d 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -40,7 +40,7 @@ template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink)
 
 proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
 proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
-              info: TLineInfo; idgen: IdGenerator): PSym
+              info: TLineInfo; idgen: IdGenerator; isDistinct = false): PSym
 
 proc createTypeBoundOps*(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo;
                          idgen: IdGenerator)
@@ -157,7 +157,7 @@ proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
   result.add(newSymNode(op))
   result.add genAddr(c, x)
 
-proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
+proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool, enforceWasMoved = false) =
   case n.kind
   of nkSym:
     if c.filterDiscriminator != nil: return
@@ -167,6 +167,8 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
         enforceDefaultOp:
       defaultOp(c, f.typ, body, x.dotField(f), b)
     else:
+      if enforceWasMoved:
+        body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x.dotField(f))
       fillBody(c, f.typ, body, x.dotField(f), b)
   of nkNilLit: discard
   of nkRecCase:
@@ -205,7 +207,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
       branch[^1] = newNodeI(nkStmtList, c.info)
 
       fillBodyObj(c, n[i].lastSon, branch[^1], x, y,
-                  enforceDefaultOp = localEnforceDefaultOp)
+                  enforceDefaultOp = localEnforceDefaultOp, enforceWasMoved = c.kind == attachedAsgn)
       if branch[^1].len == 0: inc emptyBranches
       caseStmt.add(branch)
     if emptyBranches != n.len-1:
@@ -216,13 +218,22 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
       fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
     c.filterDiscriminator = oldfilterDiscriminator
   of nkRecList:
-    for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp)
+    for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp, enforceWasMoved)
   else:
     illFormedAstLocal(n, c.g.config)
 
 proc fillBodyObjTImpl(c: var TLiftCtx; t: PType, body, x, y: PNode) =
   if t.baseClass != nil:
-    fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, x, y)
+    let dest = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
+    dest.add newNodeI(nkEmpty, c.info)
+    dest.add x
+    var src = y
+    if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
+      src = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
+      src.add newNodeI(nkEmpty, c.info)
+      src.add y
+
+    fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, dest, src)
   fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
 
 proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
@@ -279,6 +290,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
     c.kind = attachedDestructor
     fillBodyObjTImpl(c, t, body, blob, y)
     c.kind = prevKind
+
   else:
     fillBodyObjTImpl(c, t, body, x, y)
 
@@ -1034,7 +1046,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
     else:
       discard "cannot copy openArray"
 
-  of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
+  of tyFromExpr, tyError, tyBuiltInTypeClass, tyUserTypeClass,
      tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
      tyGenericParam, tyGenericBody, tyNil, tyUntyped, tyTyped,
      tyTypeDesc, tyGenericInvocation, tyForward, tyStatic:
@@ -1051,7 +1063,9 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
   assert typ.kind == tyDistinct
   let baseType = typ.elementType
   if getAttachedOp(g, baseType, kind) == nil:
-    discard produceSym(g, c, baseType, kind, info, idgen)
+    # TODO: fixme `isDistinct` is a fix for #23552; remove it after
+    # `-d:nimPreviewNonVarDestructor` becomes the default
+    discard produceSym(g, c, baseType, kind, info, idgen, isDistinct = true)
   result = getAttachedOp(g, baseType, kind)
   setAttachedOp(g, idgen.module, typ, kind, result)
 
@@ -1090,7 +1104,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
   incl result.flags, sfGeneratedOp
 
 proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
-              info: TLineInfo; idgen: IdGenerator; isDiscriminant = false): PSym =
+              info: TLineInfo; idgen: IdGenerator; isDiscriminant = false; isDistinct = false): PSym =
   if kind == attachedDup:
     return symDupPrototype(g, typ, owner, kind, info, idgen)
 
@@ -1101,7 +1115,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
                    idgen, result, info)
 
   if kind == attachedDestructor and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
-     ((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or typ.kind in {tyRef, tyString, tySequence}):
+     ((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or (typ.kind in {tyRef, tyString, tySequence} and not isDistinct)):
     dest.typ = typ
   else:
     dest.typ = makeVarType(typ.owner, typ, idgen)
@@ -1143,13 +1157,13 @@ proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   body.add newAsgnStmt(xx, yy)
 
 proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
-              info: TLineInfo; idgen: IdGenerator): PSym =
+              info: TLineInfo; idgen: IdGenerator; isDistinct = false): PSym =
   if typ.kind == tyDistinct:
     return produceSymDistinctType(g, c, typ, kind, info, idgen)
 
   result = getAttachedOp(g, typ, kind)
   if result == nil:
-    result = symPrototype(g, typ, typ.owner, kind, info, idgen)
+    result = symPrototype(g, typ, typ.owner, kind, info, idgen, isDistinct = isDistinct)
 
   var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType: typ, idgen: idgen,
                    fn: result)
diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim
index dc0b6c360..94a483299 100644
--- a/compiler/lineinfos.nim
+++ b/compiler/lineinfos.nim
@@ -92,9 +92,10 @@ type
     warnStmtListLambda = "StmtListLambda",
     warnBareExcept = "BareExcept",
     warnImplicitDefaultValue = "ImplicitDefaultValue",
-    warnGenericsIgnoredInjection = "GenericsIgnoredInjection",
+    warnIgnoredSymbolInjection = "IgnoredSymbolInjection",
     warnStdPrefix = "StdPrefix"
     warnUser = "User",
+    warnGlobalVarConstructorTemporary = "GlobalVarConstructorTemporary",
     # hints
     hintSuccess = "Success", hintSuccessX = "SuccessX",
     hintCC = "CC",
@@ -197,9 +198,10 @@ const
     warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
     warnBareExcept: "$1",
     warnImplicitDefaultValue: "$1",
-    warnGenericsIgnoredInjection: "$1",
+    warnIgnoredSymbolInjection: "$1",
     warnStdPrefix: "$1 needs the 'std' prefix",
     warnUser: "$1",
+    warnGlobalVarConstructorTemporary: "global variable '$1' initialization requires a temporary variable",
     hintSuccess: "operation successful: $#",
     # keep in sync with `testament.isSuccess`
     hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output",
@@ -266,6 +268,7 @@ const
   NotesVerbosity* = computeNotesVerbosity()
   errXMustBeCompileTime* = "'$1' can only be used in compile-time context"
   errArgsNeedRunOption* = "arguments can only be given if the '--run' option is selected"
+  errFloatToString* = "cannot convert '$1' to '$2'"
 
 type
   TFileInfo* = object
diff --git a/compiler/llstream.nim b/compiler/llstream.nim
index fa223b373..cc8148483 100644
--- a/compiler/llstream.nim
+++ b/compiler/llstream.nim
@@ -68,6 +68,7 @@ when not declared(readLineFromStdin):
   # fallback implementation:
   proc readLineFromStdin(prompt: string, line: var string): bool =
     stdout.write(prompt)
+    stdout.flushFile()
     result = readLine(stdin, line)
     if not result:
       stdout.write("\n")
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index e6b4c8f9a..d8fcf73e0 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -50,7 +50,7 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
         case x.kind
         of nkIdent: id.add(x.ident.s)
         of nkSym: id.add(x.sym.name.s)
-        of nkSymChoices:
+        of nkSymChoices, nkOpenSym:
           if x[0].kind == nkSym:
             id.add(x[0].sym.name.s)
           else:
@@ -63,6 +63,8 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
       result = n[0].sym.name
     else:
       handleError(n, origin)
+  of nkOpenSym:
+    result = considerQuotedIdent(c, n[0], origin)
   else:
     handleError(n, origin)
 
@@ -561,23 +563,33 @@ proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
   var amb: bool = false
   discard errorUseQualifier(c, info, s, amb)
 
-proc errorUseQualifier*(c: PContext; info: TLineInfo; candidates: seq[PSym]; prefix = "use one of") =
-  var err = "ambiguous identifier: '" & candidates[0].name.s & "'"
+proc ambiguousIdentifierMsg*(candidates: seq[PSym], prefix = "use one of", indent = 0): string =
+  result = ""
+  for i in 0 ..< indent:
+    result.add(' ')
+  result.add "ambiguous identifier: '" & candidates[0].name.s & "'"
   var i = 0
   for candidate in candidates:
-    if i == 0: err.add " -- $1 the following:\n" % prefix
-    else: err.add "\n"
-    err.add "  " & candidate.owner.name.s & "." & candidate.name.s
-    err.add ": " & typeToString(candidate.typ)
+    if i == 0: result.add " -- $1 the following:\n" % prefix
+    else: result.add "\n"
+    for i in 0 ..< indent:
+      result.add(' ')
+    result.add "  " & candidate.owner.name.s & "." & candidate.name.s
+    result.add ": " & typeToString(candidate.typ)
     inc i
-  localError(c.config, info, errGenerated, err)
 
-proc errorUseQualifier*(c: PContext; info:TLineInfo; choices: PNode) =
+proc errorUseQualifier*(c: PContext; info: TLineInfo; candidates: seq[PSym]) =
+  localError(c.config, info, errGenerated, ambiguousIdentifierMsg(candidates))
+
+proc ambiguousIdentifierMsg*(choices: PNode, indent = 0): string =
   var candidates = newSeq[PSym](choices.len)
   let prefix = if choices[0].typ.kind != tyProc: "use one of" else: "you need a helper proc to disambiguate"
   for i, n in choices:
     candidates[i] = n.sym
-  errorUseQualifier(c, info, candidates, prefix)
+  result = ambiguousIdentifierMsg(candidates, prefix, indent)
+
+proc errorUseQualifier*(c: PContext; info:TLineInfo; choices: PNode) =
+  localError(c.config, info, errGenerated, ambiguousIdentifierMsg(choices))
 
 proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extra = "") =
   var err: string
@@ -630,9 +642,10 @@ type
 
 const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage}
 
-proc lookUpCandidates*(c: PContext, ident: PIdent, filter: set[TSymKind]): seq[PSym] =
+proc lookUpCandidates*(c: PContext, ident: PIdent, filter: set[TSymKind],
+                       includePureEnum = false): seq[PSym] =
   result = searchInScopesFilterBy(c, ident, filter)
-  if result.len == 0:
+  if skEnumField in filter and (result.len == 0 or includePureEnum):
     result.add allPureEnumFields(c, ident)
 
 proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
@@ -665,24 +678,33 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
     c.isAmbiguous = amb
   of nkSym:
     result = n.sym
+  of nkOpenSym:
+    result = qualifiedLookUp(c, n[0], flags)
   of nkDotExpr:
     result = nil
     var m = qualifiedLookUp(c, n[0], (flags * {checkUndeclared}) + {checkModule})
     if m != nil and m.kind == skModule:
       var ident: PIdent = nil
-      if n[1].kind == nkIdent:
-        ident = n[1].ident
-      elif n[1].kind == nkAccQuoted:
+      if n[1].kind == nkAccQuoted:
         ident = considerQuotedIdent(c, n[1])
+      else:
+        # this includes sym and symchoice nodes, but since we are looking in
+        # a module, it shouldn't matter what was captured
+        ident = n[1].getPIdent
       if ident != nil:
         if m == c.module:
-          result = strTableGet(c.topLevelScope.symbols, ident)
+          var ti: TIdentIter = default(TIdentIter)
+          result = initIdentIter(ti, c.topLevelScope.symbols, ident)
+          if result != nil and nextIdentIter(ti, c.topLevelScope.symbols) != nil:
+            # another symbol exists with same name
+            c.isAmbiguous = true
         else:
+          var amb: bool = false
           if c.importModuleLookup.getOrDefault(m.name.id).len > 1:
-            var amb: bool = false
             result = errorUseQualifier(c, n.info, m, amb)
           else:
-            result = someSym(c.graph, m, ident)
+            result = someSymAmb(c.graph, m, ident, amb)
+            if amb: c.isAmbiguous = true
         if result == nil and checkUndeclared in flags:
           result = errorUndeclaredIdentifierHint(c, ident, n[1].info)
       elif n[1].kind == nkSym:
@@ -701,6 +723,10 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
     if result != nil and result.kind == skStub: loadStub(result)
 
 proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
+  if n.kind == nkOpenSym:
+    # maybe the logic in semexprs should be mirrored here instead
+    # for now it only seems this is called for `pickSym` in `getTypeIdent` 
+    return initOverloadIter(o, c, n[0])
   o.importIdx = -1
   o.marked = initIntSet()
   case n.kind
diff --git a/compiler/main.nim b/compiler/main.nim
index 0b74162a9..4c52317cf 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -22,8 +22,6 @@ import
   modules,
   modulegraphs, lineinfos, pathutils, vmprofiler
 
-# ensure NIR compiles:
-import nir / nir
 
 when defined(nimPreviewSlimSystem):
   import std/[syncio, assertions]
@@ -48,9 +46,6 @@ proc writeDepsFile(g: ModuleGraph) =
       f.writeLine(toFullPath(g.config, k))
   f.close()
 
-proc writeNinjaFile(g: ModuleGraph) =
-  discard "to implement"
-
 proc writeCMakeDepsFile(conf: ConfigRef) =
   ## write a list of C files for build systems like CMake.
   ## only updated when the C file list changes.
@@ -161,26 +156,6 @@ proc commandCompileToC(graph: ModuleGraph) =
     if optGenCDeps in graph.config.globalOptions:
       writeCMakeDepsFile(conf)
 
-proc commandCompileToNir(graph: ModuleGraph) =
-  let conf = graph.config
-  extccomp.initVars(conf)
-  if conf.symbolFiles == disabledSf:
-    if {optRun, optForceFullMake} * conf.globalOptions == {optRun}:
-      if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile):
-        # nothing changed
-        graph.config.notes = graph.config.mainPackageNotes
-        return
-
-  if not extccomp.ccHasSaneOverflow(conf):
-    conf.symbols.defineSymbol("nimEmulateOverflowChecks")
-
-  if conf.symbolFiles == disabledSf:
-    setPipeLinePass(graph, NirPass)
-  else:
-    setPipeLinePass(graph, SemPass)
-  compilePipelineProject(graph)
-  writeNinjaFile(graph)
-
 proc commandJsonScript(graph: ModuleGraph) =
   extccomp.runJsonBuildInstructions(graph.config, graph.config.jsonBuildInstructionsFile)
 
@@ -197,16 +172,13 @@ proc commandCompileToJS(graph: ModuleGraph) =
     if optGenScript in conf.globalOptions:
       writeDepsFile(graph)
 
-proc commandInteractive(graph: ModuleGraph; useNir: bool) =
+proc commandInteractive(graph: ModuleGraph) =
   graph.config.setErrorMaxHighMaybe
   initDefines(graph.config.symbols)
-  if useNir:
-    defineSymbol(graph.config.symbols, "noSignalHandler")
-  else:
-    defineSymbol(graph.config.symbols, "nimscript")
+  defineSymbol(graph.config.symbols, "nimscript")
   # note: seems redundant with -d:nimHasLibFFI
   when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
-  setPipeLinePass(graph, if useNir: NirReplPass else: InterpreterPass)
+  setPipeLinePass(graph, InterpreterPass)
   compilePipelineSystemModule(graph)
   if graph.config.commandArgs.len > 0:
     discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
@@ -293,8 +265,6 @@ proc mainCommand*(graph: ModuleGraph) =
         # and it has added this define implictly, so we must undo that here.
         # A better solution might be to fix system.nim
         undefSymbol(conf.symbols, "useNimRtl")
-    of backendNir:
-      if conf.exc == excNone: conf.exc = excGoto
     of backendInvalid: raiseAssert "unreachable"
 
   proc compileToBackend() =
@@ -305,7 +275,6 @@ proc mainCommand*(graph: ModuleGraph) =
     of backendCpp: commandCompileToC(graph)
     of backendObjc: commandCompileToC(graph)
     of backendJs: commandCompileToJS(graph)
-    of backendNir: commandCompileToNir(graph)
     of backendInvalid: raiseAssert "unreachable"
 
   template docLikeCmd(body) =
@@ -444,7 +413,7 @@ proc mainCommand*(graph: ModuleGraph) =
     wantMainModule(conf)
     commandView(graph)
     #msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
-  of cmdInteractive: commandInteractive(graph, isDefined(conf, "nir"))
+  of cmdInteractive: commandInteractive(graph)
   of cmdNimscript:
     if conf.projectIsCmd or conf.projectIsStdin: discard
     elif not fileExists(conf.projectFull):
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 75f3a3c70..77762d23a 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -11,7 +11,7 @@
 ## represents a complete Nim project. Single modules can either be kept in RAM
 ## or stored in a rod-file.
 
-import std/[intsets, tables, hashes, strtabs, algorithm]
+import std/[intsets, tables, hashes, strtabs, algorithm, os, strutils, parseutils]
 import ../dist/checksums/src/checksums/md5
 import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages, suggestsymdb
 import ic / [packed_ast, ic]
@@ -62,8 +62,6 @@ type
     CgenPass
     EvalPass
     InterpreterPass
-    NirPass
-    NirReplPass
     GenDependPass
     Docgen2TexPass
     Docgen2JsonPass
@@ -276,6 +274,25 @@ proc someSym*(g: ModuleGraph; m: PSym; name: PIdent): PSym =
   else:
     result = strTableGet(g.ifaces[m.position].interfSelect(importHidden), name)
 
+proc someSymAmb*(g: ModuleGraph; m: PSym; name: PIdent; amb: var bool): PSym =
+  let importHidden = optImportHidden in m.options
+  if isCachedModule(g, m):
+    result = nil
+    for s in interfaceSymbols(g.config, g.cache, g.packed, FileIndex(m.position), name, importHidden):
+      if result == nil:
+        # set result to the first symbol
+        result = s
+      else:
+        # another symbol found
+        amb = true
+        break
+  else:
+    var ti: TIdentIter = default(TIdentIter)
+    result = initIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden), name)
+    if result != nil and nextIdentIter(ti, g.ifaces[m.position].interfSelect(importHidden)) != nil:
+      # another symbol exists with same name
+      amb = true
+
 proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym =
   result = someSym(g, g.systemModule, name)
 
@@ -311,7 +328,7 @@ proc resolveInst(g: ModuleGraph; t: var LazyInstantiation): PInstantiation =
     t.inst = result
   assert result != nil
 
-proc resolveAttachedOp(g: ModuleGraph; t: var LazySym): PSym =
+proc resolveAttachedOp*(g: ModuleGraph; t: var LazySym): PSym =
   result = t.sym
   if result == nil:
     result = loadSymFromId(g.config, g.cache, g.packed, t.id.module, t.id.packed)
@@ -454,6 +471,49 @@ proc createMagic*(g: ModuleGraph; idgen: IdGenerator; name: string, m: TMagic):
 proc createMagic(g: ModuleGraph; name: string, m: TMagic): PSym =
   result = createMagic(g, g.idgen, name, m)
 
+proc uniqueModuleName*(conf: ConfigRef; m: PSym): string =
+  ## The unique module name is guaranteed to only contain {'A'..'Z', 'a'..'z', '0'..'9', '_'}
+  ## so that it is useful as a C identifier snippet.
+  let fid = FileIndex(m.position)
+  let path = AbsoluteFile toFullPath(conf, fid)
+  var isLib = false
+  var rel = ""
+  if path.string.startsWith(conf.libpath.string):
+    isLib = true
+    rel = relativeTo(path, conf.libpath).string
+  else:
+    rel = relativeTo(path, conf.projectPath).string
+
+  if not isLib and not belongsToProjectPackage(conf, m):
+    # special handlings for nimble packages
+    when DirSep == '\\':
+      let rel2 = replace(rel, '\\', '/')
+    else:
+      let rel2 = rel
+    const pkgs2 = "pkgs2/"
+    var start = rel2.find(pkgs2)
+    if start >= 0:
+      start += pkgs2.len
+      start += skipUntil(rel2, {'/'}, start)
+      if start+1 < rel2.len:
+        rel = "pkg/" & rel2[start+1..<rel.len] # strips paths
+
+  let trunc = if rel.endsWith(".nim"): rel.len - len(".nim") else: rel.len
+  result = newStringOfCap(trunc)
+  for i in 0..<trunc:
+    let c = rel[i]
+    case c
+    of 'a'..'z', '0'..'9':
+      result.add c
+    of {os.DirSep, os.AltSep}:
+      result.add 'Z' # because it looks a bit like '/'
+    of '.':
+      result.add 'O' # a circle
+    else:
+      # We mangle upper letters too so that there cannot
+      # be clashes with our special meanings of 'Z' and 'O'
+      result.addInt ord(c)
+
 proc registerModule*(g: ModuleGraph; m: PSym) =
   assert m != nil
   assert m.kind == skModule
@@ -465,7 +525,7 @@ proc registerModule*(g: ModuleGraph; m: PSym) =
     setLen(g.packed.pm, m.position + 1)
 
   g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[],
-                               uniqueName: rope(uniqueModuleName(g.config, FileIndex(m.position))))
+                               uniqueName: rope(uniqueModuleName(g.config, m)))
   initStrTables(g, m)
 
 proc registerModuleById*(g: ModuleGraph; m: FileIndex) =
@@ -617,7 +677,6 @@ proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
   if m != nil:
     g.suggestSymbols.del(fileIdx)
     g.suggestErrors.del(fileIdx)
-    g.resetForBackend
     incl m.flags, sfDirty
 
 proc unmarkAllDirty*(g: ModuleGraph) =
@@ -680,8 +739,6 @@ proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
 proc configComplete*(g: ModuleGraph) =
   rememberStartupConfig(g.startupPackedConfig, g.config)
 
-from std/strutils import repeat, `%`
-
 proc onProcessing*(graph: ModuleGraph, fileIdx: FileIndex, moduleStatus: string, fromModule: PSym, ) =
   let conf = graph.config
   let isNimscript = conf.isDefined("nimscript")
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 1e0a90ebd..c49ca8c9b 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -629,7 +629,7 @@ proc warningDeprecated*(conf: ConfigRef, info: TLineInfo = gCmdLineInfo, msg = "
   message(conf, info, warnDeprecated, msg)
 
 proc internalErrorImpl(conf: ConfigRef; info: TLineInfo, errMsg: string, info2: InstantiationInfo) =
-  if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return
+  if conf.cmd in {cmdIdeTools, cmdCheck} and conf.structuredErrorHook.isNil: return
   writeContext(conf, info)
   liMessage(conf, info, errInternal, errMsg, doAbort, info2)
 
@@ -651,13 +651,16 @@ template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, extraM
   let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName
   liMessage(conf, info, msg, m, doNothing, instLoc())
 
-proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
-  if i.fileIndex.int32 < 0:
+proc quotedFilename*(conf: ConfigRef; fi: FileIndex): Rope =
+  if fi.int32 < 0:
     result = makeCString "???"
   elif optExcessiveStackTrace in conf.globalOptions:
-    result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName
+    result = conf.m.fileInfos[fi.int32].quotedFullName
   else:
-    result = conf.m.fileInfos[i.fileIndex.int32].quotedName
+    result = conf.m.fileInfos[fi.int32].quotedName
+
+proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
+  quotedFilename(conf, i.fileIndex)
 
 template listMsg(title, r) =
   msgWriteln(conf, title, {msgNoUnitSep})
@@ -666,31 +669,6 @@ template listMsg(title, r) =
 proc listWarnings*(conf: ConfigRef) = listMsg("Warnings:", warnMin..warnMax)
 proc listHints*(conf: ConfigRef) = listMsg("Hints:", hintMin..hintMax)
 
-proc uniqueModuleName*(conf: ConfigRef; fid: FileIndex): string =
-  ## The unique module name is guaranteed to only contain {'A'..'Z', 'a'..'z', '0'..'9', '_'}
-  ## so that it is useful as a C identifier snippet.
-  let path = AbsoluteFile toFullPath(conf, fid)
-  let rel =
-    if path.string.startsWith(conf.libpath.string):
-      relativeTo(path, conf.libpath).string
-    else:
-      relativeTo(path, conf.projectPath).string
-  let trunc = if rel.endsWith(".nim"): rel.len - len(".nim") else: rel.len
-  result = newStringOfCap(trunc)
-  for i in 0..<trunc:
-    let c = rel[i]
-    case c
-    of 'a'..'z':
-      result.add c
-    of {os.DirSep, os.AltSep}:
-      result.add 'Z' # because it looks a bit like '/'
-    of '.':
-      result.add 'O' # a circle
-    else:
-      # We mangle upper letters and digits too so that there cannot
-      # be clashes with our special meanings of 'Z' and 'O'
-      result.addInt ord(c)
-
 proc genSuccessX*(conf: ConfigRef) =
   let mem =
     when declared(system.getMaxMem): formatSize(getMaxMem()) & " peakmem"
diff --git a/compiler/ndi.nim b/compiler/ndi.nim
index a9d9cfe79..cc18ab39f 100644
--- a/compiler/ndi.nim
+++ b/compiler/ndi.nim
@@ -29,7 +29,7 @@ proc doWrite(f: var NdiFile; s: PSym; conf: ConfigRef) =
   f.buf.add "\t"
   f.buf.addInt s.info.col.int
   f.f.write(s.name.s, "\t")
-  f.f.writeRope(s.loc.r)
+  f.f.writeRope(s.loc.snippet)
   f.f.writeLine("\t", toFullPath(conf, s.info), "\t", f.buf)
 
 template writeMangledName*(f: NdiFile; s: PSym; conf: ConfigRef) =
diff --git a/compiler/nim.nim b/compiler/nim.nim
index 3473ea443..005f11a58 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -116,9 +116,9 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
     conf.backend = backendC
 
   if conf.selectedGC == gcUnselected:
-    if conf.backend in {backendC, backendCpp, backendObjc, backendNir} or
-        (conf.cmd == cmdInteractive and isDefined(conf, "nir")) or
-        (conf.cmd in cmdDocLike and conf.backend != backendJs):
+    if conf.backend in {backendC, backendCpp, backendObjc} or
+        (conf.cmd in cmdDocLike and conf.backend != backendJs) or
+        conf.cmd == cmdGendepend:
       initOrcDefines(conf)
 
   mainCommand(graph)
diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim
deleted file mode 100644
index c8954548f..000000000
--- a/compiler/nir/ast2ir.nim
+++ /dev/null
@@ -1,2638 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-import std / [assertions, tables, sets]
-import ".." / [ast, astalgo, types, options, lineinfos, msgs, magicsys,
-  modulegraphs, renderer, transf, bitsets, trees, nimsets,
-  expanddefaults]
-from ".." / lowerings import lowerSwap, lowerTupleUnpacking
-from ".." / pathutils import customPath
-import .. / ic / bitabs
-
-import nirtypes, nirinsts, nirlineinfos, nirslots, types2ir, nirfiles
-
-when defined(nimCompilerStacktraceHints):
-  import std/stackframes
-
-type
-  ModuleCon* = ref object
-    nirm*: ref NirModule
-    types: TypesCon
-    module*: PSym
-    graph*: ModuleGraph
-    nativeIntId, nativeUIntId: TypeId
-    strPayloadId: (TypeId, TypeId)
-    idgen: IdGenerator
-    processedProcs, pendingProcsAsSet: HashSet[ItemId]
-    pendingProcs: seq[PSym] # procs we still need to generate code for
-    pendingVarsAsSet: HashSet[ItemId]
-    pendingVars: seq[PSym]
-    noModularity*: bool
-    inProc: int
-    toSymId: Table[ItemId, SymId]
-    symIdCounter: int32
-
-  ProcCon* = object
-    config*: ConfigRef
-    lit: Literals
-    lastFileKey: FileIndex
-    lastFileVal: LitId
-    labelGen: int
-    exitLabel: LabelId
-    #code*: Tree
-    blocks: seq[(PSym, LabelId)]
-    sm: SlotManager
-    idgen: IdGenerator
-    m: ModuleCon
-    prc: PSym
-    options: TOptions
-
-template code(c: ProcCon): Tree = c.m.nirm.code
-
-proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym;
-                    nirm: ref NirModule): ModuleCon =
-  #let lit = Literals() # must be shared
-  result = ModuleCon(graph: graph, types: initTypesCon(config), nirm: nirm,
-    idgen: idgen, module: module)
-  case config.target.intSize
-  of 2:
-    result.nativeIntId = Int16Id
-    result.nativeUIntId = UInt16Id
-  of 4:
-    result.nativeIntId = Int32Id
-    result.nativeUIntId = UInt16Id
-  else:
-    result.nativeIntId = Int64Id
-    result.nativeUIntId = UInt16Id
-  result.strPayloadId = strPayloadPtrType(result.types, result.nirm.types)
-  nirm.namespace = nirm.lit.strings.getOrIncl(customPath(toFullPath(config, module.info)))
-  nirm.intbits = uint32(config.target.intSize * 8)
-
-proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon =
-  result = ProcCon(m: m, sm: initSlotManager({}), prc: prc, config: config,
-    lit: m.nirm.lit, idgen: m.idgen,
-    options: if prc != nil: prc.options
-             else: config.options)
-  result.exitLabel = newLabel(result.labelGen)
-
-proc toLineInfo(c: var ProcCon; i: TLineInfo): PackedLineInfo =
-  var val: LitId
-  if c.lastFileKey == i.fileIndex:
-    val = c.lastFileVal
-  else:
-    val = c.lit.strings.getOrIncl(toFullPath(c.config, i.fileIndex))
-    # remember the entry:
-    c.lastFileKey = i.fileIndex
-    c.lastFileVal = val
-  result = pack(c.m.nirm.man, val, int32 i.line, int32 i.col)
-
-proc bestEffort(c: ProcCon): TLineInfo =
-  if c.prc != nil:
-    c.prc.info
-  else:
-    c.m.module.info
-
-proc popBlock(c: var ProcCon; oldLen: int) =
-  c.blocks.setLen(oldLen)
-
-template withBlock(labl: PSym; info: PackedLineInfo; asmLabl: LabelId; body: untyped) {.dirty.} =
-  var oldLen {.gensym.} = c.blocks.len
-  c.blocks.add (labl, asmLabl)
-  body
-  popBlock(c, oldLen)
-
-type
-  GenFlag = enum
-    gfAddrOf # load the address of the expression
-    gfToOutParam # the expression is passed to an `out` parameter
-  GenFlags = set[GenFlag]
-
-proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {})
-
-proc genScope(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) =
-  openScope c.sm
-  gen c, n, d, flags
-  closeScope c.sm
-
-proc freeTemp(c: var ProcCon; tmp: Value) =
-  let s = extractTemp(tmp)
-  if s != SymId(-1):
-    freeTemp(c.sm, s)
-
-proc freeTemps(c: var ProcCon; tmps: openArray[Value]) =
-  for t in tmps: freeTemp(c, t)
-
-proc typeToIr(m: ModuleCon; t: PType): TypeId =
-  typeToIr(m.types, m.nirm.types, t)
-
-proc allocTemp(c: var ProcCon; t: TypeId): SymId =
-  if c.m.noModularity:
-    result = allocTemp(c.sm, t, c.m.symIdCounter)
-  else:
-    result = allocTemp(c.sm, t, c.idgen.symId)
-
-const
-  ListSymId = -1
-
-proc toSymId(c: var ProcCon; s: PSym): SymId =
-  if c.m.noModularity:
-    result = c.m.toSymId.getOrDefault(s.itemId, SymId(-1))
-    if result.int < 0:
-      inc c.m.symIdCounter
-      result = SymId(c.m.symIdCounter)
-      c.m.toSymId[s.itemId] = result
-      when ListSymId != -1:
-        if result.int == ListSymId or s.name.s == "echoBinSafe":
-          echo result.int, " is ", s.name.s, " ", c.m.graph.config $ s.info, " ", s.flags
-          writeStackTrace()
-  else:
-    result = SymId(s.itemId.item)
-
-proc getTemp(c: var ProcCon; n: PNode): Value =
-  let info = toLineInfo(c, n.info)
-  let t = typeToIr(c.m, n.typ)
-  let tmp = allocTemp(c, t)
-  c.code.addSummon info, tmp, t
-  result = localToValue(info, tmp)
-
-proc getTemp(c: var ProcCon; t: TypeId; info: PackedLineInfo): Value =
-  let tmp = allocTemp(c, t)
-  c.code.addSummon info, tmp, t
-  result = localToValue(info, tmp)
-
-proc gen(c: var ProcCon; n: PNode; flags: GenFlags = {}) =
-  var tmp = default(Value)
-  gen(c, n, tmp, flags)
-  freeTemp c, tmp
-
-proc genScope(c: var ProcCon; n: PNode; flags: GenFlags = {}) =
-  openScope c.sm
-  gen c, n, flags
-  closeScope c.sm
-
-proc genx(c: var ProcCon; n: PNode; flags: GenFlags = {}): Value =
-  result = default(Value)
-  gen(c, n, result, flags)
-  assert Tree(result).len > 0, $n
-
-proc clearDest(c: var ProcCon; n: PNode; d: var Value) {.inline.} =
-  when false:
-    if n.typ.isNil or n.typ.kind == tyVoid:
-      let s = extractTemp(d)
-      if s != SymId(-1):
-        freeLoc(c.sm, s)
-
-proc isNotOpr(n: PNode): bool =
-  n.kind in nkCallKinds and n[0].kind == nkSym and n[0].sym.magic == mNot
-
-proc jmpBack(c: var ProcCon; n: PNode; lab: LabelId) =
-  c.code.gotoLabel toLineInfo(c, n.info), GotoLoop, lab
-
-type
-  JmpKind = enum opcFJmp, opcTJmp
-
-proc xjmp(c: var ProcCon; n: PNode; jk: JmpKind; v: Value): LabelId =
-  result = newLabel(c.labelGen)
-  let info = toLineInfo(c, n.info)
-  buildTyped c.code, info, Select, Bool8Id:
-    c.code.copyTree Tree(v)
-    build c.code, info, SelectPair:
-      build c.code, info, SelectValue:
-        c.code.boolVal(c.lit.numbers, info, jk == opcTJmp)
-      c.code.gotoLabel info, Goto, result
-
-proc patch(c: var ProcCon; n: PNode; L: LabelId) =
-  addLabel c.code, toLineInfo(c, n.info), Label, L
-
-proc genWhile(c: var ProcCon; n: PNode) =
-  # lab1:
-  #   cond, tmp
-  #   fjmp tmp, lab2
-  #   body
-  #   jmp lab1
-  # lab2:
-  let info = toLineInfo(c, n.info)
-  let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel)
-  withBlock(nil, info, lab1):
-    if isTrue(n[0]):
-      c.gen(n[1])
-      c.jmpBack(n, lab1)
-    elif isNotOpr(n[0]):
-      var tmp = c.genx(n[0][1])
-      let lab2 = c.xjmp(n, opcTJmp, tmp)
-      c.freeTemp(tmp)
-      c.gen(n[1])
-      c.jmpBack(n, lab1)
-      c.patch(n, lab2)
-    else:
-      var tmp = c.genx(n[0])
-      let lab2 = c.xjmp(n, opcFJmp, tmp)
-      c.freeTemp(tmp)
-      c.gen(n[1])
-      c.jmpBack(n, lab1)
-      c.patch(n, lab2)
-
-proc genBlock(c: var ProcCon; n: PNode; d: var Value) =
-  openScope c.sm
-  let info = toLineInfo(c, n.info)
-  let lab1 = newLabel(c.labelGen)
-
-  withBlock(n[0].sym, info, lab1):
-    c.gen(n[1], d)
-
-  c.code.addLabel(info, Label, lab1)
-  closeScope c.sm
-  c.clearDest(n, d)
-
-proc jumpTo(c: var ProcCon; n: PNode; L: LabelId) =
-  c.code.addLabel(toLineInfo(c, n.info), Goto, L)
-
-proc genBreak(c: var ProcCon; n: PNode) =
-  if n[0].kind == nkSym:
-    for i in countdown(c.blocks.len-1, 0):
-      if c.blocks[i][0] == n[0].sym:
-        c.jumpTo n, c.blocks[i][1]
-        return
-    localError(c.config, n.info, "NIR problem: cannot find 'break' target")
-  else:
-    c.jumpTo n, c.blocks[c.blocks.high][1]
-
-proc genIf(c: var ProcCon; n: PNode; d: var Value) =
-  #  if (!expr1) goto lab1;
-  #    thenPart
-  #    goto LEnd
-  #  lab1:
-  #  if (!expr2) goto lab2;
-  #    thenPart2
-  #    goto LEnd
-  #  lab2:
-  #    elsePart
-  #  Lend:
-  if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
-  var ending = newLabel(c.labelGen)
-  for i in 0..<n.len:
-    var it = n[i]
-    if it.len == 2:
-      let info = toLineInfo(c, it[0].info)
-      var elsePos: LabelId
-      if isNotOpr(it[0]):
-        let tmp = c.genx(it[0][1])
-        elsePos = c.xjmp(it[0][1], opcTJmp, tmp) # if true
-        c.freeTemp tmp
-      else:
-        let tmp = c.genx(it[0])
-        elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false
-        c.freeTemp tmp
-      c.clearDest(n, d)
-      if isEmptyType(it[1].typ): # maybe noreturn call, don't touch `d`
-        c.genScope(it[1])
-      else:
-        c.genScope(it[1], d) # then part
-      if i < n.len-1:
-        c.jumpTo it[1], ending
-      c.patch(it, elsePos)
-    else:
-      c.clearDest(n, d)
-      if isEmptyType(it[0].typ): # maybe noreturn call, don't touch `d`
-        c.genScope(it[0])
-      else:
-        c.genScope(it[0], d)
-  c.patch(n, ending)
-  c.clearDest(n, d)
-
-proc tempToDest(c: var ProcCon; n: PNode; d: var Value; tmp: Value) =
-  if isEmpty(d):
-    d = tmp
-  else:
-    let info = toLineInfo(c, n.info)
-    buildTyped c.code, info, Asgn, typeToIr(c.m, n.typ):
-      c.code.copyTree d
-      c.code.copyTree tmp
-    freeTemp(c, tmp)
-
-proc genAndOr(c: var ProcCon; n: PNode; opc: JmpKind; d: var Value) =
-  #   asgn d, a
-  #   tjmp|fjmp lab1
-  #   asgn d, b
-  # lab1:
-  var tmp = getTemp(c, n)
-  c.gen(n[1], tmp)
-  let lab1 = c.xjmp(n, opc, tmp)
-  c.gen(n[2], tmp)
-  c.patch(n, lab1)
-  tempToDest c, n, d, tmp
-
-proc unused(c: var ProcCon; n: PNode; x: Value) {.inline.} =
-  if hasValue(x):
-    #debug(n)
-    localError(c.config, n.info, "not unused")
-
-proc caseValue(c: var ProcCon; n: PNode) =
-  let info = toLineInfo(c, n.info)
-  build c.code, info, SelectValue:
-    let x = genx(c, n)
-    c.code.copyTree x
-    freeTemp(c, x)
-
-proc caseRange(c: var ProcCon; n: PNode) =
-  let info = toLineInfo(c, n.info)
-  build c.code, info, SelectRange:
-    let x = genx(c, n[0])
-    let y = genx(c, n[1])
-    c.code.copyTree x
-    c.code.copyTree y
-    freeTemp(c, y)
-    freeTemp(c, x)
-
-proc addUseCodegenProc(c: var ProcCon; dest: var Tree; name: string; info: PackedLineInfo) =
-  let cp = getCompilerProc(c.m.graph, name)
-  let theProc = c.genx newSymNode(cp)
-  copyTree c.code, theProc
-
-template buildCond(useNegation: bool; cond: typed; body: untyped) =
-  let lab = newLabel(c.labelGen)
-  buildTyped c.code, info, Select, Bool8Id:
-    c.code.copyTree cond
-    build c.code, info, SelectPair:
-      build c.code, info, SelectValue:
-        c.code.boolVal(c.lit.numbers, info, useNegation)
-      c.code.gotoLabel info, Goto, lab
-
-  body
-  c.code.addLabel info, Label, lab
-
-template buildIf(cond: typed; body: untyped) =
-  buildCond false, cond, body
-
-template buildIfNot(cond: typed; body: untyped) =
-  buildCond true, cond, body
-
-template buildIfThenElse(cond: typed; then, otherwise: untyped) =
-  let lelse = newLabel(c.labelGen)
-  let lend = newLabel(c.labelGen)
-  buildTyped c.code, info, Select, Bool8Id:
-    c.code.copyTree cond
-    build c.code, info, SelectPair:
-      build c.code, info, SelectValue:
-        c.code.boolVal(c.lit.numbers, info, false)
-      c.code.gotoLabel info, Goto, lelse
-
-  then()
-  c.code.gotoLabel info, Goto, lend
-  c.code.addLabel info, Label, lelse
-  otherwise()
-  c.code.addLabel info, Label, lend
-
-include stringcases
-
-proc genCase(c: var ProcCon; n: PNode; d: var Value) =
-  if not isEmptyType(n.typ):
-    if isEmpty(d): d = getTemp(c, n)
-  else:
-    unused(c, n, d)
-
-  if n[0].typ.skipTypes(abstractInst).kind == tyString:
-    genStringCase(c, n, d)
-    return
-
-  var sections = newSeqOfCap[LabelId](n.len-1)
-  let ending = newLabel(c.labelGen)
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[0])
-  buildTyped c.code, info, Select, typeToIr(c.m, n[0].typ):
-    c.code.copyTree tmp
-    for i in 1..<n.len:
-      let section = newLabel(c.labelGen)
-      sections.add section
-      let it = n[i]
-      let itinfo = toLineInfo(c, it.info)
-      build c.code, itinfo, SelectPair:
-        build c.code, itinfo, SelectList:
-          for j in 0..<it.len-1:
-            if it[j].kind == nkRange:
-              caseRange c, it[j]
-            else:
-              caseValue c, it[j]
-        c.code.addLabel itinfo, Goto, section
-  c.freeTemp tmp
-  for i in 1..<n.len:
-    let it = n[i]
-    let itinfo = toLineInfo(c, it.info)
-    c.code.addLabel itinfo, Label, sections[i-1]
-    c.gen it.lastSon
-    if i != n.len-1:
-      c.code.addLabel itinfo, Goto, ending
-  c.code.addLabel info, Label, ending
-
-proc rawCall(c: var ProcCon; info: PackedLineInfo; opc: Opcode; t: TypeId; args: var openArray[Value]) =
-  buildTyped c.code, info, opc, t:
-    if opc in {CheckedCall, CheckedIndirectCall}:
-      c.code.addLabel info, CheckedGoto, c.exitLabel
-    for a in mitems(args):
-      c.code.copyTree a
-      freeTemp c, a
-
-proc canRaiseDisp(c: ProcCon; n: PNode): bool =
-  # we assume things like sysFatal cannot raise themselves
-  if n.kind == nkSym and {sfNeverRaises, sfImportc, sfCompilerProc} * n.sym.flags != {}:
-    result = false
-  elif optPanics in c.config.globalOptions or
-      (n.kind == nkSym and sfSystemModule in getModule(n.sym).flags and
-       sfSystemRaisesDefect notin n.sym.flags):
-    # we know we can be strict:
-    result = canRaise(n)
-  else:
-    # we have to be *very* conservative:
-    result = canRaiseConservative(n)
-
-proc genCall(c: var ProcCon; n: PNode; d: var Value) =
-  let canRaise = canRaiseDisp(c, n[0])
-
-  let opc = if n[0].kind == nkSym and n[0].sym.kind in routineKinds:
-              (if canRaise: CheckedCall else: Call)
-            else:
-              (if canRaise: CheckedIndirectCall else: IndirectCall)
-  let info = toLineInfo(c, n.info)
-
-  # In the IR we cannot nest calls. Thus we use two passes:
-  var args: seq[Value] = @[]
-  var t = n[0].typ
-  if t != nil: t = t.skipTypes(abstractInst)
-  args.add genx(c, n[0])
-  for i in 1..<n.len:
-    if t != nil and i < t.len:
-      if isCompileTimeOnly(t[i]): discard
-      elif isOutParam(t[i]): args.add genx(c, n[i], {gfToOutParam})
-      else: args.add genx(c, n[i])
-    else:
-      args.add genx(c, n[i])
-
-  let tb = typeToIr(c.m, n.typ)
-  if not isEmptyType(n.typ):
-    if isEmpty(d): d = getTemp(c, n)
-    # XXX Handle problematic aliasing here: `a = f_canRaise(a)`.
-    buildTyped c.code, info, Asgn, tb:
-      c.code.copyTree d
-      rawCall c, info, opc, tb, args
-  else:
-    rawCall c, info, opc, tb, args
-  freeTemps c, args
-
-proc genRaise(c: var ProcCon; n: PNode) =
-  let info = toLineInfo(c, n.info)
-  let tb = typeToIr(c.m, n[0].typ)
-
-  let d = genx(c, n[0])
-  buildTyped c.code, info, SetExc, tb:
-    c.code.copyTree d
-  c.freeTemp(d)
-  c.code.addLabel info, Goto, c.exitLabel
-
-proc genReturn(c: var ProcCon; n: PNode) =
-  if n[0].kind != nkEmpty:
-    gen(c, n[0])
-  # XXX Block leave actions?
-  let info = toLineInfo(c, n.info)
-  c.code.addLabel info, Goto, c.exitLabel
-
-proc genTry(c: var ProcCon; n: PNode; d: var Value) =
-  if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
-  var endings: seq[LabelId] = @[]
-  let ehPos = newLabel(c.labelGen)
-  let oldExitLab = c.exitLabel
-  c.exitLabel = ehPos
-  if isEmptyType(n[0].typ): # maybe noreturn call, don't touch `d`
-    c.gen(n[0])
-  else:
-    c.gen(n[0], d)
-  c.clearDest(n, d)
-
-  # Add a jump past the exception handling code
-  let jumpToFinally = newLabel(c.labelGen)
-  c.jumpTo n, jumpToFinally
-  # This signals where the body ends and where the exception handling begins
-  c.patch(n, ehPos)
-  c.exitLabel = oldExitLab
-  for i in 1..<n.len:
-    let it = n[i]
-    if it.kind != nkFinally:
-      # first opcExcept contains the end label of the 'except' block:
-      let endExcept = newLabel(c.labelGen)
-      for j in 0..<it.len - 1:
-        assert(it[j].kind == nkType)
-        let typ = it[j].typ.skipTypes(abstractPtrs-{tyTypeDesc})
-        let itinfo = toLineInfo(c, it[j].info)
-        build c.code, itinfo, TestExc:
-          c.code.addTyped itinfo, typeToIr(c.m, typ)
-      if it.len == 1:
-        let itinfo = toLineInfo(c, it.info)
-        build c.code, itinfo, TestExc:
-          c.code.addTyped itinfo, VoidId
-      let body = it.lastSon
-      if isEmptyType(body.typ): # maybe noreturn call, don't touch `d`
-        c.gen(body)
-      else:
-        c.gen(body, d)
-      c.clearDest(n, d)
-      if i < n.len:
-        endings.add newLabel(c.labelGen)
-      c.patch(it, endExcept)
-  let fin = lastSon(n)
-  # we always generate an 'opcFinally' as that pops the safepoint
-  # from the stack if no exception is raised in the body.
-  c.patch(fin, jumpToFinally)
-  #c.gABx(fin, opcFinally, 0, 0)
-  for endPos in endings: c.patch(n, endPos)
-  if fin.kind == nkFinally:
-    c.gen(fin[0])
-    c.clearDest(n, d)
-  #c.gABx(fin, opcFinallyEnd, 0, 0)
-
-template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
-proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym)
-
-proc genField(c: var ProcCon; n: PNode; d: var Value) =
-  var pos: int
-  if n.kind != nkSym or n.sym.kind != skField:
-    localError(c.config, n.info, "no field symbol")
-    pos = 0
-  else:
-    pos = n.sym.position
-  d.addImmediateVal toLineInfo(c, n.info), pos
-
-proc genIndex(c: var ProcCon; n: PNode; arr: PType; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  if arr.skipTypes(abstractInst).kind == tyArray and
-      (let offset = firstOrd(c.config, arr); offset != Zero):
-    let x = c.genx(n)
-    buildTyped d, info, Sub, c.m.nativeIntId:
-      copyTree d.Tree, x
-      d.addImmediateVal toLineInfo(c, n.info), toInt(offset)
-  else:
-    c.gen(n, d)
-  if optBoundsCheck in c.options:
-    let idx = move d
-    build d, info, CheckedIndex:
-      d.Tree.addLabel info, CheckedGoto, c.exitLabel
-      copyTree d.Tree, idx
-      let x = toInt64 lengthOrd(c.config, arr)
-      d.addIntVal c.lit.numbers, info, c.m.nativeIntId, x
-
-proc rawGenNew(c: var ProcCon; d: Value; refType: PType; ninfo: TLineInfo; needsInit: bool) =
-  assert refType.kind == tyRef
-  let baseType = refType.elementType
-
-  let info = toLineInfo(c, ninfo)
-  let codegenProc = magicsys.getCompilerProc(c.m.graph,
-    if needsInit: "nimNewObj" else: "nimNewObjUninit")
-  let refTypeIr = typeToIr(c.m, refType)
-  buildTyped c.code, info, Asgn, refTypeIr:
-    copyTree c.code, d
-    buildTyped c.code, info, Cast, refTypeIr:
-      buildTyped c.code, info, Call, VoidPtrId:
-        let theProc = c.genx newSymNode(codegenProc, ninfo)
-        copyTree c.code, theProc
-        c.code.addImmediateVal info, int(getSize(c.config, baseType))
-        c.code.addImmediateVal info, int(getAlign(c.config, baseType))
-
-proc genNew(c: var ProcCon; n: PNode; needsInit: bool) =
-  # If in doubt, always follow the blueprint of the C code generator for `mm:orc`.
-  let refType = n[1].typ.skipTypes(abstractInstOwned)
-  let d = genx(c, n[1])
-  rawGenNew c, d, refType, n.info, needsInit
-  freeTemp c, d
-
-proc genNewSeqOfCap(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let seqtype = skipTypes(n.typ, abstractVarRange)
-  let baseType = seqtype.elementType
-  var a = c.genx(n[1])
-  if isEmpty(d): d = getTemp(c, n)
-  # $1.len = 0
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
-      copyTree c.code, d
-      c.code.addImmediateVal info, 0
-    c.code.addImmediateVal info, 0
-  # $1.p = ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3))
-  let payloadPtr = seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[0]
-  buildTyped c.code, info, Asgn, payloadPtr:
-    # $1.p
-    buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
-      copyTree c.code, d
-      c.code.addImmediateVal info, 1
-    # ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3))
-    buildTyped c.code, info, Cast, payloadPtr:
-      buildTyped c.code, info, Call, VoidPtrId:
-        let codegenProc = magicsys.getCompilerProc(c.m.graph, "newSeqPayloadUninit")
-        let theProc = c.genx newSymNode(codegenProc, n.info)
-        copyTree c.code, theProc
-        copyTree c.code, a
-        c.code.addImmediateVal info, int(getSize(c.config, baseType))
-        c.code.addImmediateVal info, int(getAlign(c.config, baseType))
-  freeTemp c, a
-
-proc genNewSeqPayload(c: var ProcCon; info: PackedLineInfo; d, b: Value; seqtype: PType) =
-  let baseType = seqtype.elementType
-  # $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3))
-  let payloadPtr = seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[0]
-
-  # $1.len = $2
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
-      copyTree c.code, d
-      c.code.addImmediateVal info, 0
-    copyTree c.code, b
-
-  buildTyped c.code, info, Asgn, payloadPtr:
-    # $1.p
-    buildTyped c.code, info, FieldAt, typeToIr(c.m, seqtype):
-      copyTree c.code, d
-      c.code.addImmediateVal info, 1
-    # ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3))
-    buildTyped c.code, info, Cast, payloadPtr:
-      buildTyped c.code, info, Call, VoidPtrId:
-        let codegenProc = magicsys.getCompilerProc(c.m.graph, "newSeqPayload")
-        let theProc = c.genx newSymNode(codegenProc)
-        copyTree c.code, theProc
-        copyTree c.code, b
-        c.code.addImmediateVal info, int(getSize(c.config, baseType))
-        c.code.addImmediateVal info, int(getAlign(c.config, baseType))
-
-proc genNewSeq(c: var ProcCon; n: PNode) =
-  let info = toLineInfo(c, n.info)
-  let seqtype = skipTypes(n[1].typ, abstractVarRange)
-  var d = c.genx(n[1])
-  var b = c.genx(n[2])
-
-  genNewSeqPayload(c, info, d, b, seqtype)
-
-  freeTemp c, b
-  freeTemp c, d
-
-template intoDest*(d: var Value; info: PackedLineInfo; typ: TypeId; body: untyped) =
-  if typ == VoidId:
-    body(c.code)
-  elif isEmpty(d):
-    body(Tree(d))
-  else:
-    buildTyped c.code, info, Asgn, typ:
-      copyTree c.code, d
-      body(c.code)
-
-template valueIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: PType; body: untyped) =
-  if isEmpty(d):
-    body(Tree d)
-  else:
-    buildTyped c.code, info, Asgn, typeToIr(c.m, typ):
-      copyTree c.code, d
-      body(c.code)
-
-template constrIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: PType; body: untyped) =
-  var tmp = default(Value)
-  body(Tree tmp)
-  if isEmpty(d):
-    d = tmp
-  else:
-    buildTyped c.code, info, Asgn, typeToIr(c.m, typ):
-      copyTree c.code, d
-      copyTree c.code, tmp
-
-proc genBinaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[1])
-  let tmp2 = c.genx(n[2])
-  let t = typeToIr(c.m, n.typ)
-  template body(target) =
-    buildTyped target, info, opc, t:
-      if opc in {CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedMod}:
-        target.addLabel info, CheckedGoto, c.exitLabel
-      copyTree target, tmp
-      copyTree target, tmp2
-  intoDest d, info, t, body
-  c.freeTemp(tmp)
-  c.freeTemp(tmp2)
-
-proc genCmpOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[1])
-  let tmp2 = c.genx(n[2])
-  let t = typeToIr(c.m, n[1].typ)
-  template body(target) =
-    buildTyped target, info, opc, t:
-      copyTree target, tmp
-      copyTree target, tmp2
-  intoDest d, info, Bool8Id, body
-  c.freeTemp(tmp)
-  c.freeTemp(tmp2)
-
-proc genUnaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[1])
-  let t = typeToIr(c.m, n.typ)
-  template body(target) =
-    buildTyped target, info, opc, t:
-      copyTree target, tmp
-  intoDest d, info, t, body
-  c.freeTemp(tmp)
-
-proc genIncDec(c: var ProcCon; n: PNode; opc: Opcode) =
-  let info = toLineInfo(c, n.info)
-  let t = typeToIr(c.m, skipTypes(n[1].typ, abstractVar))
-
-  let d = c.genx(n[1])
-  let tmp = c.genx(n[2])
-  # we produce code like:  i = i + 1
-  buildTyped c.code, info, Asgn, t:
-    copyTree c.code, d
-    buildTyped c.code, info, opc, t:
-      if opc in {CheckedAdd, CheckedSub}:
-        c.code.addLabel info, CheckedGoto, c.exitLabel
-      copyTree c.code, d
-      copyTree c.code, tmp
-  c.freeTemp(tmp)
-  #c.genNarrow(n[1], d)
-  c.freeTemp(d)
-
-proc genArrayLen(c: var ProcCon; n: PNode; d: var Value) =
-  #echo c.m.graph.config $ n.info, " ", n
-  let info = toLineInfo(c, n.info)
-  var a = n[1]
-  #if a.kind == nkHiddenAddr: a = a[0]
-  var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses)
-  case typ.kind
-  of tyOpenArray, tyVarargs:
-    let xa = c.genx(a)
-    template body(target) =
-      buildTyped target, info, FieldAt, typeToIr(c.m, typ):
-        copyTree target, xa
-        target.addImmediateVal info, 1 # (p, len)-pair so len is at index 1
-    intoDest d, info, c.m.nativeIntId, body
-
-  of tyCstring:
-    let xa = c.genx(a)
-    if isEmpty(d): d = getTemp(c, n)
-    buildTyped c.code, info, Call, c.m.nativeIntId:
-      let codegenProc = magicsys.getCompilerProc(c.m.graph, "nimCStrLen")
-      assert codegenProc != nil
-      let theProc = c.genx newSymNode(codegenProc, n.info)
-      copyTree c.code, theProc
-      copyTree c.code, xa
-
-  of tyString, tySequence:
-    let xa = c.genx(a)
-
-    if typ.kind == tySequence:
-      # we go through a temporary here because people write bullshit code.
-      if isEmpty(d): d = getTemp(c, n)
-
-    template body(target) =
-      buildTyped target, info, FieldAt, typeToIr(c.m, typ):
-        copyTree target, xa
-        target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
-    intoDest d, info, c.m.nativeIntId, body
-
-  of tyArray:
-    template body(target) =
-      target.addIntVal(c.lit.numbers, info, c.m.nativeIntId, toInt lengthOrd(c.config, typ))
-    intoDest d, info, c.m.nativeIntId, body
-  else: internalError(c.config, n.info, "genArrayLen()")
-
-proc genUnaryMinus(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[1])
-  let t = typeToIr(c.m, n.typ)
-  template body(target) =
-    buildTyped target, info, Sub, t:
-      # Little hack: This works because we know that `0.0` is all 0 bits:
-      target.addIntVal(c.lit.numbers, info, t, 0)
-      copyTree target, tmp
-  intoDest d, info, t, body
-  c.freeTemp(tmp)
-
-proc genHigh(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let t = typeToIr(c.m, n.typ)
-  var x = default(Value)
-  genArrayLen(c, n, x)
-  template body(target) =
-    buildTyped target, info, Sub, t:
-      copyTree target, x
-      target.addIntVal(c.lit.numbers, info, t, 1)
-  intoDest d, info, t, body
-  c.freeTemp x
-
-proc genBinaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string) =
-  let info = toLineInfo(c, n.info)
-  let xa = c.genx(n[1])
-  let xb = c.genx(n[2])
-  if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
-
-  let t = typeToIr(c.m, n.typ)
-  template body(target) =
-    buildTyped target, info, Call, t:
-      let codegenProc = magicsys.getCompilerProc(c.m.graph, compilerProc)
-      #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info)
-      let theProc = c.genx newSymNode(codegenProc, n.info)
-      copyTree target, theProc
-      copyTree target, xa
-      copyTree target, xb
-
-  intoDest d, info, t, body
-  c.freeTemp xb
-  c.freeTemp xa
-
-proc genUnaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string; argAt = 1) =
-  let info = toLineInfo(c, n.info)
-  let xa = c.genx(n[argAt])
-  if isEmpty(d) and not isEmptyType(n.typ): d = getTemp(c, n)
-
-  let t = typeToIr(c.m, n.typ)
-  template body(target) =
-    buildTyped target, info, Call, t:
-      let codegenProc = magicsys.getCompilerProc(c.m.graph, compilerProc)
-      let theProc = c.genx newSymNode(codegenProc, n.info)
-      copyTree target, theProc
-      copyTree target, xa
-
-  intoDest d, info, t, body
-  c.freeTemp xa
-
-proc genEnumToStr(c: var ProcCon; n: PNode; d: var Value) =
-  let t = n[1].typ.skipTypes(abstractInst+{tyRange})
-  let toStrProc = getToStringProc(c.m.graph, t)
-  # XXX need to modify this logic for IC.
-  var nb = copyTree(n)
-  nb[0] = newSymNode(toStrProc)
-  gen(c, nb, d)
-
-proc genOf(c: var ProcCon; n: PNode; d: var Value) =
-  genUnaryOp c, n, d, TestOf
-
-template sizeOfLikeMsg(name): string =
-  "'" & name & "' requires '.importc' types to be '.completeStruct'"
-
-proc genIsNil(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[1])
-  let t = typeToIr(c.m, n[1].typ)
-  template body(target) =
-    buildTyped target, info, Eq, t:
-      copyTree target, tmp
-      addNilVal target, info, t
-  intoDest d, info, Bool8Id, body
-  c.freeTemp(tmp)
-
-proc fewCmps(conf: ConfigRef; s: PNode): bool =
-  # this function estimates whether it is better to emit code
-  # for constructing the set or generating a bunch of comparisons directly
-  if s.kind != nkCurly:
-    result = false
-  elif (getSize(conf, s.typ) <= conf.target.intSize) and (nfAllConst in s.flags):
-    result = false            # it is better to emit the set generation code
-  elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
-    result = true             # better not emit the set if int is basetype!
-  else:
-    result = s.len <= 8  # 8 seems to be a good value
-
-proc genInBitset(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let b = c.genx(n[2])
-
-  let t = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
-  let setType = typeToIr(c.m, n[1].typ)
-  let mask =
-    case t
-    of UInt8Id: 7
-    of UInt16Id: 15
-    of UInt32Id: 31
-    else: 63
-  let expansion = if t == UInt64Id: UInt64Id else: c.m.nativeUIntId
-    # "(($1              &(1U<<((NU)($2)&7U)))!=0)"  - or -
-    # "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)"
-
-  template body(target) =
-    buildTyped target, info, BoolNot, Bool8Id:
-      buildTyped target, info, Eq, t:
-        buildTyped target, info, BitAnd, t:
-          if c.m.nirm.types[setType].kind != ArrayTy:
-            copyTree target, a
-          else:
-            buildTyped target, info, ArrayAt, setType:
-              copyTree target, a
-              buildTyped target, info, BitShr, t:
-                buildTyped target, info, Cast, expansion:
-                  copyTree target, b
-                addIntVal target, c.lit.numbers, info, expansion, 3
-
-          buildTyped target, info, BitShl, t:
-            addIntVal target, c.lit.numbers, info, t, 1
-            buildTyped target, info, BitAnd, t:
-              buildTyped target, info, Cast, expansion:
-                copyTree target, b
-              addIntVal target, c.lit.numbers, info, expansion, mask
-        addIntVal target, c.lit.numbers, info, t, 0
-  intoDest d, info, t, body
-
-  c.freeTemp(b)
-  c.freeTemp(a)
-
-proc genInSet(c: var ProcCon; n: PNode; d: var Value) =
-  let g {.cursor.} = c.m.graph
-  if n[1].kind == nkCurly and fewCmps(g.config, n[1]):
-    # a set constructor but not a constant set:
-    # do not emit the set, but generate a bunch of comparisons; and if we do
-    # so, we skip the unnecessary range check: This is a semantical extension
-    # that code now relies on. :-/ XXX
-    let elem = if n[2].kind in {nkChckRange, nkChckRange64}: n[2][0]
-               else: n[2]
-    let curly = n[1]
-    var ex: PNode = nil
-    for it in curly:
-      var test: PNode
-      if it.kind == nkRange:
-        test = newTree(nkCall, g.operators.opAnd.newSymNode,
-          newTree(nkCall, g.operators.opLe.newSymNode, it[0], elem), # a <= elem
-          newTree(nkCall, g.operators.opLe.newSymNode, elem, it[1])
-        )
-      else:
-        test = newTree(nkCall, g.operators.opEq.newSymNode, elem, it)
-      test.typ = getSysType(g, it.info, tyBool)
-
-      if ex == nil: ex = test
-      else: ex = newTree(nkCall, g.operators.opOr.newSymNode, ex, test)
-
-    if ex == nil:
-      let info = toLineInfo(c, n.info)
-      template body(target) =
-        boolVal target, c.lit.numbers, info, false
-      intoDest d, info, Bool8Id, body
-    else:
-      gen c, ex, d
-  else:
-    genInBitset c, n, d
-
-proc genCard(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let t = typeToIr(c.m, n.typ)
-
-  let setType = typeToIr(c.m, n[1].typ)
-  if isEmpty(d): d = getTemp(c, n)
-
-  buildTyped c.code, info, Asgn, t:
-    copyTree c.code, d
-    buildTyped c.code, info, Call, t:
-      if c.m.nirm.types[setType].kind == ArrayTy:
-        let codegenProc = magicsys.getCompilerProc(c.m.graph, "cardSet")
-        let theProc = c.genx newSymNode(codegenProc, n.info)
-        copyTree c.code, theProc
-        buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType):
-          copyTree c.code, a
-        c.code.addImmediateVal info, int(getSize(c.config, n[1].typ))
-      elif t == UInt64Id:
-        let codegenProc = magicsys.getCompilerProc(c.m.graph, "countBits64")
-        let theProc = c.genx newSymNode(codegenProc, n.info)
-        copyTree c.code, theProc
-        copyTree c.code, a
-      else:
-        let codegenProc = magicsys.getCompilerProc(c.m.graph, "countBits32")
-        let theProc = c.genx newSymNode(codegenProc, n.info)
-        copyTree c.code, theProc
-        buildTyped c.code, info, Cast, UInt32Id:
-          copyTree c.code, a
-  freeTemp c, a
-
-proc genEqSet(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let b = c.genx(n[2])
-  let t = typeToIr(c.m, n.typ)
-
-  let setType = typeToIr(c.m, n[1].typ)
-
-  if c.m.nirm.types[setType].kind == ArrayTy:
-    if isEmpty(d): d = getTemp(c, n)
-
-    buildTyped c.code, info, Asgn, t:
-      copyTree c.code, d
-      buildTyped c.code, info, Eq, t:
-        buildTyped c.code, info, Call, t:
-          let codegenProc = magicsys.getCompilerProc(c.m.graph, "nimCmpMem")
-          let theProc = c.genx newSymNode(codegenProc, n.info)
-          copyTree c.code, theProc
-          buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType):
-            copyTree c.code, a
-          buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, setType):
-            copyTree c.code, b
-          c.code.addImmediateVal info, int(getSize(c.config, n[1].typ))
-        c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
-
-  else:
-    template body(target) =
-      buildTyped target, info, Eq, setType:
-        copyTree target, a
-        copyTree target, b
-    intoDest d, info, Bool8Id, body
-
-  freeTemp c, b
-  freeTemp c, a
-
-proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: int): (SymId, LabelId, LabelId) =
-  let tmp = allocTemp(c, c.m.nativeIntId)
-  c.code.addSummon info, tmp, c.m.nativeIntId
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    c.code.addSymUse info, tmp
-    c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, first
-  let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel)
-  result = (tmp, lab1, newLabel(c.labelGen))
-
-  buildTyped c.code, info, Select, Bool8Id:
-    buildTyped c.code, info, Lt, c.m.nativeIntId:
-      c.code.addSymUse info, tmp
-      c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, last
-    build c.code, info, SelectPair:
-      build c.code, info, SelectValue:
-        c.code.boolVal(c.lit.numbers, info, false)
-      c.code.gotoLabel info, Goto, result[2]
-
-proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: Value): (SymId, LabelId, LabelId) =
-  let tmp = allocTemp(c, c.m.nativeIntId)
-  c.code.addSummon info, tmp, c.m.nativeIntId
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    c.code.addSymUse info, tmp
-    copyTree c.code, first
-  let lab1 = c.code.addNewLabel(c.labelGen, info, LoopLabel)
-  result = (tmp, lab1, newLabel(c.labelGen))
-
-  buildTyped c.code, info, Select, Bool8Id:
-    buildTyped c.code, info, Le, c.m.nativeIntId:
-      c.code.addSymUse info, tmp
-      copyTree c.code, last
-    build c.code, info, SelectPair:
-      build c.code, info, SelectValue:
-        c.code.boolVal(c.lit.numbers, info, false)
-      c.code.gotoLabel info, Goto, result[2]
-
-proc endLoop(c: var ProcCon; info: PackedLineInfo; s: SymId; back, exit: LabelId) =
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    c.code.addSymUse info, s
-    buildTyped c.code, info, Add, c.m.nativeIntId:
-      c.code.addSymUse info, s
-      c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
-  c.code.addLabel info, GotoLoop, back
-  c.code.addLabel info, Label, exit
-  freeTemp(c.sm, s)
-
-proc genLeSet(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let b = c.genx(n[2])
-  let t = typeToIr(c.m, n.typ)
-
-  let setType = typeToIr(c.m, n[1].typ)
-
-  if c.m.nirm.types[setType].kind == ArrayTy:
-    let elemType = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
-    if isEmpty(d): d = getTemp(c, n)
-    #    "for ($1 = 0; $1 < $2; $1++):"
-    #    "  $3 = (($4[$1] & ~ $5[$1]) == 0)"
-    #    "  if (!$3) break;"
-    let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, int(getSize(c.config, n[1].typ)))
-    buildTyped c.code, info, Asgn, Bool8Id:
-      copyTree c.code, d
-      buildTyped c.code, info, Eq, elemType:
-        buildTyped c.code, info, BitAnd, elemType:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, a
-            c.code.addSymUse info, idx
-          buildTyped c.code, info, BitNot, elemType:
-            buildTyped c.code, info, ArrayAt, setType:
-              copyTree c.code, b
-              c.code.addSymUse info, idx
-        c.code.addIntVal c.lit.numbers, info, elemType, 0
-
-    # if !$3: break
-    buildTyped c.code, info, Select, Bool8Id:
-      c.code.copyTree d
-      build c.code, info, SelectPair:
-        build c.code, info, SelectValue:
-          c.code.boolVal(c.lit.numbers, info, false)
-        c.code.gotoLabel info, Goto, endLabel
-
-    endLoop(c, info, idx, backLabel, endLabel)
-  else:
-    # "(($1 & ~ $2)==0)"
-    template body(target) =
-      buildTyped target, info, Eq, setType:
-        buildTyped target, info, BitAnd, setType:
-          copyTree target, a
-          buildTyped target, info, BitNot, setType:
-            copyTree target, b
-        target.addIntVal c.lit.numbers, info, setType, 0
-
-    intoDest d, info, Bool8Id, body
-
-  freeTemp c, b
-  freeTemp c, a
-
-proc genLtSet(c: var ProcCon; n: PNode; d: var Value) =
-  localError(c.m.graph.config, n.info, "`<` for sets not implemented")
-
-proc genBinarySet(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let b = c.genx(n[2])
-  let t = typeToIr(c.m, n.typ)
-
-  let setType = typeToIr(c.m, n[1].typ)
-
-  if c.m.nirm.types[setType].kind == ArrayTy:
-    let elemType = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
-    if isEmpty(d): d = getTemp(c, n)
-    #    "for ($1 = 0; $1 < $2; $1++):"
-    #    "  $3 = (($4[$1] & ~ $5[$1]) == 0)"
-    #    "  if (!$3) break;"
-    let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, int(getSize(c.config, n[1].typ)))
-    buildTyped c.code, info, Asgn, elemType:
-      buildTyped c.code, info, ArrayAt, setType:
-        copyTree c.code, d
-        c.code.addSymUse info, idx
-      buildTyped c.code, info, (if m == mPlusSet: BitOr else: BitAnd), elemType:
-        buildTyped c.code, info, ArrayAt, setType:
-          copyTree c.code, a
-          c.code.addSymUse info, idx
-        if m == mMinusSet:
-          buildTyped c.code, info, BitNot, elemType:
-            buildTyped c.code, info, ArrayAt, setType:
-              copyTree c.code, b
-              c.code.addSymUse info, idx
-        else:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, b
-            c.code.addSymUse info, idx
-
-    endLoop(c, info, idx, backLabel, endLabel)
-  else:
-    # "(($1 & ~ $2)==0)"
-    template body(target) =
-      buildTyped target, info, (if m == mPlusSet: BitOr else: BitAnd), setType:
-        copyTree target, a
-        if m == mMinusSet:
-          buildTyped target, info, BitNot, setType:
-            copyTree target, b
-        else:
-          copyTree target, b
-
-    intoDest d, info, setType, body
-
-  freeTemp c, b
-  freeTemp c, a
-
-proc genInclExcl(c: var ProcCon; n: PNode; m: TMagic) =
-  let info = toLineInfo(c, n.info)
-  let a = c.genx(n[1])
-  let b = c.genx(n[2])
-
-  let setType = typeToIr(c.m, n[1].typ)
-
-  let t = bitsetBasetype(c.m.types, c.m.nirm.types, n[1].typ)
-  let mask =
-    case t
-    of UInt8Id: 7
-    of UInt16Id: 15
-    of UInt32Id: 31
-    else: 63
-
-  buildTyped c.code, info, Asgn, setType:
-    if c.m.nirm.types[setType].kind == ArrayTy:
-      if m == mIncl:
-        # $1[(NU)($2)>>3] |=(1U<<($2&7U))
-        buildTyped c.code, info, ArrayAt, setType:
-          copyTree c.code, a
-          buildTyped c.code, info, BitShr, t:
-            buildTyped c.code, info, Cast, c.m.nativeUIntId:
-              copyTree c.code, b
-            addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-        buildTyped c.code, info, BitOr, t:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, a
-            buildTyped c.code, info, BitShr, t:
-              buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                copyTree c.code, b
-              addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-          buildTyped c.code, info, BitShl, t:
-            c.code.addIntVal c.lit.numbers, info, t, 1
-            buildTyped c.code, info, BitAnd, t:
-              copyTree c.code, b
-              c.code.addIntVal c.lit.numbers, info, t, 7
-      else:
-        # $1[(NU)($2)>>3] &= ~(1U<<($2&7U))
-        buildTyped c.code, info, ArrayAt, setType:
-          copyTree c.code, a
-          buildTyped c.code, info, BitShr, t:
-            buildTyped c.code, info, Cast, c.m.nativeUIntId:
-              copyTree c.code, b
-            addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-        buildTyped c.code, info, BitAnd, t:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, a
-            buildTyped c.code, info, BitShr, t:
-              buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                copyTree c.code, b
-              addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-          buildTyped c.code, info, BitNot, t:
-            buildTyped c.code, info, BitShl, t:
-              c.code.addIntVal c.lit.numbers, info, t, 1
-              buildTyped c.code, info, BitAnd, t:
-                copyTree c.code, b
-                c.code.addIntVal c.lit.numbers, info, t, 7
-
-    else:
-      copyTree c.code, a
-      if m == mIncl:
-        # $1 |= ((NU8)1)<<(($2) & 7)
-        buildTyped c.code, info, BitOr, setType:
-          copyTree c.code, a
-          buildTyped c.code, info, BitShl, t:
-            c.code.addIntVal c.lit.numbers, info, t, 1
-            buildTyped c.code, info, BitAnd, t:
-              copyTree c.code, b
-              c.code.addIntVal c.lit.numbers, info, t, mask
-      else:
-        # $1 &= ~(((NU8)1) << (($2) & 7))
-        buildTyped c.code, info, BitAnd, setType:
-          copyTree c.code, a
-          buildTyped c.code, info, BitNot, t:
-            buildTyped c.code, info, BitShl, t:
-              c.code.addIntVal c.lit.numbers, info, t, 1
-              buildTyped c.code, info, BitAnd, t:
-                copyTree c.code, b
-                c.code.addIntVal c.lit.numbers, info, t, mask
-  freeTemp c, b
-  freeTemp c, a
-
-proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) =
-  # example: { a..b, c, d, e, f..g }
-  # we have to emit an expression of the form:
-  # nimZeroMem(tmp, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c);
-  # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g);
-  let info = toLineInfo(c, n.info)
-  let setType = typeToIr(c.m, n.typ)
-  let size = int(getSize(c.config, n.typ))
-  let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ)
-  let mask =
-    case t
-    of UInt8Id: 7
-    of UInt16Id: 15
-    of UInt32Id: 31
-    else: 63
-
-  if isEmpty(d): d = getTemp(c, n)
-  if c.m.nirm.types[setType].kind != ArrayTy:
-    buildTyped c.code, info, Asgn, setType:
-      copyTree c.code, d
-      c.code.addIntVal c.lit.numbers, info, t, 0
-
-    for it in n:
-      if it.kind == nkRange:
-        let a = genx(c, it[0])
-        let b = genx(c, it[1])
-        let (idx, backLabel, endLabel) = beginCountLoop(c, info, a, b)
-        buildTyped c.code, info, Asgn, setType:
-          copyTree c.code, d
-          buildTyped c.code, info, BitAnd, setType:
-            copyTree c.code, d
-            buildTyped c.code, info, BitNot, t:
-              buildTyped c.code, info, BitShl, t:
-                c.code.addIntVal c.lit.numbers, info, t, 1
-                buildTyped c.code, info, BitAnd, t:
-                  c.code.addSymUse info, idx
-                  c.code.addIntVal c.lit.numbers, info, t, mask
-
-        endLoop(c, info, idx, backLabel, endLabel)
-        freeTemp c, b
-        freeTemp c, a
-
-      else:
-        let a = genx(c, it)
-        buildTyped c.code, info, Asgn, setType:
-          copyTree c.code, d
-          buildTyped c.code, info, BitAnd, setType:
-            copyTree c.code, d
-            buildTyped c.code, info, BitNot, t:
-              buildTyped c.code, info, BitShl, t:
-                c.code.addIntVal c.lit.numbers, info, t, 1
-                buildTyped c.code, info, BitAnd, t:
-                  copyTree c.code, a
-                  c.code.addIntVal c.lit.numbers, info, t, mask
-        freeTemp c, a
-
-  else:
-    # init loop:
-    let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, size)
-    buildTyped c.code, info, Asgn, t:
-      copyTree c.code, d
-      c.code.addIntVal c.lit.numbers, info, t, 0
-    endLoop(c, info, idx, backLabel, endLabel)
-
-    # incl elements:
-    for it in n:
-      if it.kind == nkRange:
-        let a = genx(c, it[0])
-        let b = genx(c, it[1])
-        let (idx, backLabel, endLabel) = beginCountLoop(c, info, a, b)
-
-        buildTyped c.code, info, Asgn, t:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, d
-            buildTyped c.code, info, BitShr, t:
-              buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                c.code.addSymUse info, idx
-              addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-          buildTyped c.code, info, BitOr, t:
-            buildTyped c.code, info, ArrayAt, setType:
-              copyTree c.code, d
-              buildTyped c.code, info, BitShr, t:
-                buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                  c.code.addSymUse info, idx
-                addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-            buildTyped c.code, info, BitShl, t:
-              c.code.addIntVal c.lit.numbers, info, t, 1
-              buildTyped c.code, info, BitAnd, t:
-                c.code.addSymUse info, idx
-                c.code.addIntVal c.lit.numbers, info, t, 7
-
-        endLoop(c, info, idx, backLabel, endLabel)
-        freeTemp c, b
-        freeTemp c, a
-
-      else:
-        let a = genx(c, it)
-        # $1[(NU)($2)>>3] |=(1U<<($2&7U))
-        buildTyped c.code, info, Asgn, t:
-          buildTyped c.code, info, ArrayAt, setType:
-            copyTree c.code, d
-            buildTyped c.code, info, BitShr, t:
-              buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                copyTree c.code, a
-              addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-          buildTyped c.code, info, BitOr, t:
-            buildTyped c.code, info, ArrayAt, setType:
-              copyTree c.code, d
-              buildTyped c.code, info, BitShr, t:
-                buildTyped c.code, info, Cast, c.m.nativeUIntId:
-                  copyTree c.code, a
-                addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3
-            buildTyped c.code, info, BitShl, t:
-              c.code.addIntVal c.lit.numbers, info, t, 1
-              buildTyped c.code, info, BitAnd, t:
-                copyTree c.code, a
-                c.code.addIntVal c.lit.numbers, info, t, 7
-        freeTemp c, a
-
-proc genSetConstr(c: var ProcCon; n: PNode; d: var Value) =
-  if isDeepConstExpr(n):
-    let info = toLineInfo(c, n.info)
-    let setType = typeToIr(c.m, n.typ)
-    let size = int(getSize(c.config, n.typ))
-    let cs = toBitSet(c.config, n)
-
-    if c.m.nirm.types[setType].kind != ArrayTy:
-      template body(target) =
-        target.addIntVal c.lit.numbers, info, setType, cast[BiggestInt](bitSetToWord(cs, size))
-      intoDest d, info, setType, body
-    else:
-      let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ)
-      template body(target) =
-        buildTyped target, info, ArrayConstr, setType:
-          for i in 0..high(cs):
-            target.addIntVal c.lit.numbers, info, t, int64 cs[i]
-      intoDest d, info, setType, body
-  else:
-    genSetConstrDyn c, n, d
-
-proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  #   <Nim code>
-  #   s = "Hello " & name & ", how do you feel?" & 'z'
-  #
-  #   <generated code>
-  #  {
-  #    string tmp0;
-  #    ...
-  #    tmp0 = rawNewString(6 + 17 + 1 + s2->len);
-  #    // we cannot generate s = rawNewString(...) here, because
-  #    // ``s`` may be used on the right side of the expression
-  #    appendString(tmp0, strlit_1);
-  #    appendString(tmp0, name);
-  #    appendString(tmp0, strlit_2);
-  #    appendChar(tmp0, 'z');
-  #    asgn(s, tmp0);
-  #  }
-  var args: seq[Value] = @[]
-  var argsRuntimeLen: seq[Value] = @[]
-
-  var precomputedLen = 0
-  for i in 1 ..< n.len:
-    let it = n[i]
-    args.add genx(c, it)
-    if skipTypes(it.typ, abstractVarRange).kind == tyChar:
-      inc precomputedLen
-    elif it.kind in {nkStrLit..nkTripleStrLit}:
-      inc precomputedLen, it.strVal.len
-    else:
-      argsRuntimeLen.add args[^1]
-
-  # generate length computation:
-  var tmpLen = allocTemp(c, c.m.nativeIntId)
-  buildTyped c.code, info, Asgn, c.m.nativeIntId:
-    c.code.addSymUse info, tmpLen
-    c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, precomputedLen
-  for a in mitems(argsRuntimeLen):
-    buildTyped c.code, info, Asgn, c.m.nativeIntId:
-      c.code.addSymUse info, tmpLen
-      buildTyped c.code, info, CheckedAdd, c.m.nativeIntId:
-        c.code.addLabel info, CheckedGoto, c.exitLabel
-        c.code.addSymUse info, tmpLen
-        buildTyped c.code, info, FieldAt, typeToIr(c.m, n.typ):
-          copyTree c.code, a
-          c.code.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
-
-  var tmpStr = getTemp(c, n)
-  #    ^ because of aliasing, we always go through a temporary
-  let t = typeToIr(c.m, n.typ)
-  buildTyped c.code, info, Asgn, t:
-    copyTree c.code, tmpStr
-    buildTyped c.code, info, Call, t:
-      let codegenProc = magicsys.getCompilerProc(c.m.graph, "rawNewString")
-      #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info)
-      let theProc = c.genx newSymNode(codegenProc, n.info)
-      copyTree c.code, theProc
-      c.code.addSymUse info, tmpLen
-  freeTemp c.sm, tmpLen
-
-  for i in 1 ..< n.len:
-    let it = n[i]
-    let isChar = skipTypes(it.typ, abstractVarRange).kind == tyChar
-    buildTyped c.code, info, Call, VoidId:
-      let codegenProc = magicsys.getCompilerProc(c.m.graph,
-        (if isChar: "appendChar" else: "appendString"))
-      #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info)
-      let theProc = c.genx newSymNode(codegenProc, n.info)
-      copyTree c.code, theProc
-      buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, t):
-        copyTree c.code, tmpStr
-      copyTree c.code, args[i-1]
-    freeTemp c, args[i-1]
-
-  if isEmpty(d):
-    d = tmpStr
-  else:
-    # XXX Test that this does not cause memory leaks!
-    buildTyped c.code, info, Asgn, t:
-      copyTree c.code, d
-      copyTree c.code, tmpStr
-
-proc genDefault(c: var ProcCon; n: PNode; d: var Value) =
-  let m = expandDefault(n.typ, n.info)
-  gen c, m, d
-
-proc genWasMoved(c: var ProcCon; n: PNode) =
-  let n1 = n[1].skipAddr
-  # XXX We need a way to replicate this logic or better yet a better
-  # solution for injectdestructors.nim:
-  #if c.withinBlockLeaveActions > 0 and notYetAlive(n1):
-  var d = c.genx(n1)
-  assert not isEmpty(d)
-  let m = expandDefault(n1.typ, n1.info)
-  gen c, m, d
-
-proc genMove(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  let n1 = n[1].skipAddr
-  var a = c.genx(n1)
-  if n.len == 4:
-    # generated by liftdestructors:
-    let src = c.genx(n[2])
-    # if ($1.p == $2.p) goto lab1
-    let lab1 = newLabel(c.labelGen)
-
-    let n1t = typeToIr(c.m, n1.typ)
-    let payloadType = seqPayloadPtrType(c.m.types, c.m.nirm.types, n1.typ)[0]
-    buildTyped c.code, info, Select, Bool8Id:
-      buildTyped c.code, info, Eq, payloadType:
-        buildTyped c.code, info, FieldAt, n1t:
-          copyTree c.code, a
-          c.code.addImmediateVal info, 1 # (len, p)-pair
-        buildTyped c.code, info, FieldAt, n1t:
-          copyTree c.code, src
-          c.code.addImmediateVal info, 1 # (len, p)-pair
-
-      build c.code, info, SelectPair:
-        build c.code, info, SelectValue:
-          c.code.boolVal(c.lit.numbers, info, true)
-        c.code.gotoLabel info, Goto, lab1
-
-    gen(c, n[3])
-    c.patch n, lab1
-
-    buildTyped c.code, info, Asgn, typeToIr(c.m, n1.typ):
-      copyTree c.code, a
-      copyTree c.code, src
-
-  else:
-    if isEmpty(d): d = getTemp(c, n)
-    buildTyped c.code, info, Asgn, typeToIr(c.m, n1.typ):
-      copyTree c.code, d
-      copyTree c.code, a
-    var op = getAttachedOp(c.m.graph, n.typ, attachedWasMoved)
-    if op == nil or skipTypes(n1.typ, abstractVar+{tyStatic}).kind in {tyOpenArray, tyVarargs}:
-      let m = expandDefault(n1.typ, n1.info)
-      gen c, m, a
-    else:
-      var opB = c.genx(newSymNode(op))
-      buildTyped c.code, info, Call, typeToIr(c.m, n.typ):
-        copyTree c.code, opB
-        buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, typeToIr(c.m, n1.typ)):
-          copyTree c.code, a
-
-template fieldAt(x: Value; i: int; t: TypeId): Tree =
-  var result = default(Tree)
-  buildTyped result, info, FieldAt, t:
-    copyTree result, x
-    result.addImmediateVal info, i
-  result
-
-template eqNil(x: Tree; t: TypeId): Tree =
-  var result = default(Tree)
-  buildTyped result, info, Eq, t:
-    copyTree result, x
-    result.addNilVal info, t
-  result
-
-template eqZero(x: Tree): Tree =
-  var result = default(Tree)
-  buildTyped result, info, Eq, c.m.nativeIntId:
-    copyTree result, x
-    result.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
-  result
-
-template bitOp(x: Tree; opc: Opcode; y: int): Tree =
-  var result = default(Tree)
-  buildTyped result, info, opc, c.m.nativeIntId:
-    copyTree result, x
-    result.addIntVal c.lit.numbers, info, c.m.nativeIntId, y
-  result
-
-proc genDestroySeq(c: var ProcCon; n: PNode; t: PType) =
-  let info = toLineInfo(c, n.info)
-  let strLitFlag = 1 shl (c.m.graph.config.target.intSize * 8 - 2) # see also NIM_STRLIT_FLAG
-
-  let x = c.genx(n[1])
-  let baseType = t.elementType
-
-  let seqType = typeToIr(c.m, t)
-  let p = fieldAt(x, 0, seqType)
-
-  # if $1.p != nil and ($1.p.cap and NIM_STRLIT_FLAG) == 0:
-  #   alignedDealloc($1.p, NIM_ALIGNOF($2))
-  buildIfNot p.eqNil(seqType):
-    buildIf fieldAt(Value(p), 0, seqPayloadPtrType(c.m.types, c.m.nirm.types, t)[0]).bitOp(BitAnd, 0).eqZero():
-      let codegenProc = getCompilerProc(c.m.graph, "alignedDealloc")
-      buildTyped c.code, info, Call, VoidId:
-        let theProc = c.genx newSymNode(codegenProc, n.info)
-        copyTree c.code, theProc
-        copyTree c.code, p
-        c.code.addImmediateVal info, int(getAlign(c.config, baseType))
-
-  freeTemp c, x
-
-proc genDestroy(c: var ProcCon; n: PNode) =
-  let t = n[1].typ.skipTypes(abstractInst)
-  case t.kind
-  of tyString:
-    var unused = default(Value)
-    genUnaryCp(c, n, unused, "nimDestroyStrV1")
-  of tySequence:
-    genDestroySeq(c, n, t)
-  else: discard "nothing to do"
-
-type
-  IndexFor = enum
-    ForSeq, ForStr, ForOpenArray, ForArray
-
-proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PType): Value =
-  if optBoundsCheck in c.options:
-    let info = toLineInfo(c, n.info)
-    result = default(Value)
-    let idx = genx(c, n)
-    build result, info, CheckedIndex:
-      result.Tree.addLabel info, CheckedGoto, c.exitLabel
-      copyTree result.Tree, idx
-      case kind
-      of ForSeq, ForStr:
-        buildTyped result, info, FieldAt, typeToIr(c.m, arr):
-          copyTree result.Tree, a
-          result.addImmediateVal info, 0 # (len, p)-pair
-      of ForOpenArray:
-        buildTyped result, info, FieldAt, typeToIr(c.m, arr):
-          copyTree result.Tree, a
-          result.addImmediateVal info, 1 # (p, len)-pair
-      of ForArray:
-        let x = toInt64 lengthOrd(c.config, arr)
-        result.addIntVal c.lit.numbers, info, c.m.nativeIntId, x
-    freeTemp c, idx
-  else:
-    result = genx(c, n)
-
-proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo;
-                    x: Value; n: PNode; arrType: PType) =
-  let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.elementType))
-  case arrType.kind
-  of tyString, tySequence:
-    let checkKind = if arrType.kind == tyString: ForStr else: ForSeq
-    let pay = if checkKind == ForStr: c.m.strPayloadId
-              else: seqPayloadPtrType(c.m.types, c.m.nirm.types, arrType)
-
-    let y = genIndexCheck(c, n[2], x, checkKind, arrType)
-    let z = genIndexCheck(c, n[3], x, checkKind, arrType)
-
-    buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
-      target.addImmediateVal info, 0
-      buildTyped target, info, AddrOf, elemType:
-        buildTyped target, info, DerefArrayAt, pay[1]:
-          buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-            copyTree target, x
-            target.addImmediateVal info, 1 # (len, p)-pair
-          copyTree target, y
-
-      # len:
-      target.addImmediateVal info, 1
-      buildTyped target, info, Add, c.m.nativeIntId:
-        buildTyped target, info, Sub, c.m.nativeIntId:
-          copyTree target, z
-          copyTree target, y
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
-
-    freeTemp c, z
-    freeTemp c, y
-  of tyArray:
-    # XXX This evaluates the index check for `y` twice.
-    # This check is also still insufficient for non-zero based arrays.
-    let y = genIndexCheck(c, n[2], x, ForArray, arrType)
-    let z = genIndexCheck(c, n[3], x, ForArray, arrType)
-
-    buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
-      target.addImmediateVal info, 0
-      buildTyped target, info, AddrOf, elemType:
-        buildTyped target, info, ArrayAt, typeToIr(c.m, arrType):
-          copyTree target, x
-          copyTree target, y
-
-      target.addImmediateVal info, 1
-      buildTyped target, info, Add, c.m.nativeIntId:
-        buildTyped target, info, Sub, c.m.nativeIntId:
-          copyTree target, z
-          copyTree target, y
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
-
-    freeTemp c, z
-    freeTemp c, y
-  of tyOpenArray:
-    # XXX This evaluates the index check for `y` twice.
-    let y = genIndexCheck(c, n[2], x, ForOpenArray, arrType)
-    let z = genIndexCheck(c, n[3], x, ForOpenArray, arrType)
-    let pay = openArrayPayloadType(c.m.types, c.m.nirm.types, arrType)
-
-    buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ):
-      target.addImmediateVal info, 0
-      buildTyped target, info, AddrOf, elemType:
-        buildTyped target, info, DerefArrayAt, pay:
-          buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-            copyTree target, x
-            target.addImmediateVal info, 0 # (p, len)-pair
-          copyTree target, y
-
-      target.addImmediateVal info, 1
-      buildTyped target, info, Add, c.m.nativeIntId:
-        buildTyped target, info, Sub, c.m.nativeIntId:
-          copyTree target, z
-          copyTree target, y
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1
-
-    freeTemp c, z
-    freeTemp c, y
-  else:
-    raiseAssert "addSliceFields: " & typeToString(arrType)
-
-proc genSlice(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-
-  let x = c.genx(n[1])
-
-  let arrType = n[1].typ.skipTypes(abstractVar)
-
-  template body(target) =
-    c.addSliceFields target, info, x, n, arrType
-
-  valueIntoDest c, info, d, arrType, body
-  freeTemp c, x
-
-proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
-  case m
-  of mAnd: c.genAndOr(n, opcFJmp, d)
-  of mOr: c.genAndOr(n, opcTJmp, d)
-  of mPred, mSubI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedSub else: Sub)
-  of mSucc, mAddI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedAdd else: Add)
-  of mInc:
-    unused(c, n, d)
-    c.genIncDec(n, if optOverflowCheck in c.options: CheckedAdd else: Add)
-  of mDec:
-    unused(c, n, d)
-    c.genIncDec(n, if optOverflowCheck in c.options: CheckedSub else: Sub)
-  of mOrd, mChr, mUnown:
-    c.gen(n[1], d)
-  of generatedMagics:
-    genCall(c, n, d)
-  of mNew, mNewFinalize:
-    unused(c, n, d)
-    c.genNew(n, needsInit = true)
-  of mNewSeq:
-    unused(c, n, d)
-    c.genNewSeq(n)
-  of mNewSeqOfCap: c.genNewSeqOfCap(n, d)
-  of mNewString, mNewStringOfCap, mExit: c.genCall(n, d)
-  of mLengthOpenArray, mLengthArray, mLengthSeq, mLengthStr:
-    genArrayLen(c, n, d)
-  of mMulI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMul else: Mul)
-  of mDivI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedDiv else: Div)
-  of mModI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMod else: Mod)
-  of mAddF64: genBinaryOp(c, n, d, Add)
-  of mSubF64: genBinaryOp(c, n, d, Sub)
-  of mMulF64: genBinaryOp(c, n, d, Mul)
-  of mDivF64: genBinaryOp(c, n, d, Div)
-  of mShrI: genBinaryOp(c, n, d, BitShr)
-  of mShlI: genBinaryOp(c, n, d, BitShl)
-  of mAshrI: genBinaryOp(c, n, d, BitShr)
-  of mBitandI: genBinaryOp(c, n, d, BitAnd)
-  of mBitorI: genBinaryOp(c, n, d, BitOr)
-  of mBitxorI: genBinaryOp(c, n, d, BitXor)
-  of mAddU: genBinaryOp(c, n, d, Add)
-  of mSubU: genBinaryOp(c, n, d, Sub)
-  of mMulU: genBinaryOp(c, n, d, Mul)
-  of mDivU: genBinaryOp(c, n, d, Div)
-  of mModU: genBinaryOp(c, n, d, Mod)
-  of mEqI, mEqB, mEqEnum, mEqCh:
-    genCmpOp(c, n, d, Eq)
-  of mLeI, mLeEnum, mLeCh, mLeB:
-    genCmpOp(c, n, d, Le)
-  of mLtI, mLtEnum, mLtCh, mLtB:
-    genCmpOp(c, n, d, Lt)
-  of mEqF64: genCmpOp(c, n, d, Eq)
-  of mLeF64: genCmpOp(c, n, d, Le)
-  of mLtF64: genCmpOp(c, n, d, Lt)
-  of mLePtr, mLeU: genCmpOp(c, n, d, Le)
-  of mLtPtr, mLtU: genCmpOp(c, n, d, Lt)
-  of mEqProc, mEqRef:
-    genCmpOp(c, n, d, Eq)
-  of mXor: genBinaryOp(c, n, d, BitXor)
-  of mNot: genUnaryOp(c, n, d, BoolNot)
-  of mUnaryMinusI, mUnaryMinusI64:
-    genUnaryMinus(c, n, d)
-    #genNarrow(c, n, d)
-  of mUnaryMinusF64: genUnaryMinus(c, n, d)
-  of mUnaryPlusI, mUnaryPlusF64: gen(c, n[1], d)
-  of mBitnotI:
-    genUnaryOp(c, n, d, BitNot)
-    when false:
-      # XXX genNarrowU modified, do not narrow signed types
-      let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
-      let size = getSize(c.config, t)
-      if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
-        c.gABC(n, opcNarrowU, d, TRegister(size*8))
-  of mStrToStr, mEnsureMove: c.gen n[1], d
-  of mBoolToStr: genUnaryCp(c, n, d, "nimBoolToStr")
-  of mCharToStr: genUnaryCp(c, n, d, "nimCharToStr")
-  of mCStrToStr: genUnaryCp(c, n, d, "cstrToNimstr")
-  of mEnumToStr: genEnumToStr(c, n, d)
-
-  of mEqStr: genBinaryCp(c, n, d, "eqStrings")
-  of mEqCString: genCall(c, n, d)
-  of mLeStr: genBinaryCp(c, n, d, "leStrings")
-  of mLtStr: genBinaryCp(c, n, d, "ltStrings")
-
-  of mSetLengthStr:
-    unused(c, n, d)
-    let nb = copyTree(n)
-    nb[1] = makeAddr(nb[1], c.m.idgen)
-    genBinaryCp(c, nb, d, "setLengthStrV2")
-
-  of mSetLengthSeq:
-    unused(c, n, d)
-    let nb = copyTree(n)
-    nb[1] = makeAddr(nb[1], c.m.idgen)
-    genCall(c, nb, d)
-
-  of mSwap:
-    unused(c, n, d)
-    c.gen(lowerSwap(c.m.graph, n, c.m.idgen,
-      if c.prc == nil: c.m.module else: c.prc), d)
-  of mParseBiggestFloat:
-    genCall c, n, d
-  of mHigh:
-    c.genHigh n, d
-
-  of mEcho:
-    unused(c, n, d)
-    genUnaryCp c, n, d, "echoBinSafe"
-
-  of mAppendStrCh:
-    unused(c, n, d)
-    let nb = copyTree(n)
-    nb[1] = makeAddr(nb[1], c.m.idgen)
-    genBinaryCp(c, nb, d, "nimAddCharV1")
-  of mMinI, mMaxI, mAbsI, mDotDot:
-    c.genCall(n, d)
-  of mSizeOf:
-    localError(c.config, n.info, sizeOfLikeMsg("sizeof"))
-  of mAlignOf:
-    localError(c.config, n.info, sizeOfLikeMsg("alignof"))
-  of mOffsetOf:
-    localError(c.config, n.info, sizeOfLikeMsg("offsetof"))
-  of mRunnableExamples:
-    discard "just ignore any call to runnableExamples"
-  of mOf: genOf(c, n, d)
-  of mAppendStrStr:
-    unused(c, n, d)
-    let nb = copyTree(n)
-    nb[1] = makeAddr(nb[1], c.m.idgen)
-    genBinaryCp(c, nb, d, "nimAddStrV1")
-  of mAppendSeqElem:
-    unused(c, n, d)
-    let nb = copyTree(n)
-    nb[1] = makeAddr(nb[1], c.m.idgen)
-    genCall(c, nb, d)
-  of mIsNil: genIsNil(c, n, d)
-  of mInSet: genInSet(c, n, d)
-  of mCard: genCard(c, n, d)
-  of mEqSet: genEqSet(c, n, d)
-  of mLeSet: genLeSet(c, n, d)
-  of mLtSet: genLtSet(c, n, d)
-  of mMulSet: genBinarySet(c, n, d, m)
-  of mPlusSet: genBinarySet(c, n, d, m)
-  of mMinusSet: genBinarySet(c, n, d, m)
-  of mIncl, mExcl:
-    unused(c, n, d)
-    genInclExcl(c, n, m)
-  of mConStrStr: genStrConcat(c, n, d)
-  of mDefault, mZeroDefault:
-    genDefault c, n, d
-  of mMove: genMove(c, n, d)
-  of mWasMoved, mReset:
-    unused(c, n, d)
-    genWasMoved(c, n)
-  of mDestroy: genDestroy(c, n)
-  #of mAccessEnv: unaryExpr(d, n, d, "$1.ClE_0")
-  #of mAccessTypeField: genAccessTypeField(c, n, d)
-  of mSlice: genSlice(c, n, d)
-  of mTrace: discard "no code to generate"
-  else:
-    # mGCref, mGCunref: unused by ORC
-    globalError(c.config, n.info, "cannot generate code for: " & $m)
-
-proc canElimAddr(n: PNode; idgen: IdGenerator): PNode =
-  result = nil
-  case n[0].kind
-  of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
-    var m = n[0][0]
-    if m.kind in {nkDerefExpr, nkHiddenDeref}:
-      # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
-      result = copyNode(n[0])
-      result.add m[0]
-      if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
-        result.typ = n.typ
-      elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
-        result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    var m = n[0][1]
-    if m.kind in {nkDerefExpr, nkHiddenDeref}:
-      # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
-      result = copyNode(n[0])
-      result.add n[0][0]
-      result.add m[0]
-      if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
-        result.typ = n.typ
-      elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
-        result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen)
-  else:
-    if n[0].kind in {nkDerefExpr, nkHiddenDeref}:
-      # addr ( deref ( x )) --> x
-      result = n[0][0]
-
-proc genAddr(c: var ProcCon; n: PNode; d: var Value, flags: GenFlags) =
-  if (let m = canElimAddr(n, c.m.idgen); m != nil):
-    gen(c, m, d, flags)
-    return
-
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[0], flags)
-  template body(target) =
-    buildTyped target, info, AddrOf, typeToIr(c.m, n.typ):
-      copyTree target, tmp
-
-  valueIntoDest c, info, d, n.typ, body
-  freeTemp c, tmp
-
-proc genDeref(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(n[0], flags)
-  template body(target) =
-    buildTyped target, info, Load, typeToIr(c.m, n.typ):
-      copyTree target, tmp
-
-  valueIntoDest c, info, d, n.typ, body
-  freeTemp c, tmp
-
-proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; tmp: Value; typ: PType) =
-  let arrType = typ.skipTypes(abstractVar)
-  let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.elementType))
-  case arrType.kind
-  of tyString:
-    let t = typeToIr(c.m, typ)
-    target.addImmediateVal info, 0
-    buildTyped target, info, AddrOf, elemType:
-      buildTyped target, info, DerefArrayAt, c.m.strPayloadId[1]:
-        buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-          copyTree target, tmp
-          target.addImmediateVal info, 1 # (len, p)-pair
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
-    # len:
-    target.addImmediateVal info, 1
-    buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-      copyTree target, tmp
-      target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
-
-  of tySequence:
-    let t = typeToIr(c.m, typ)
-    target.addImmediateVal info, 0
-    buildTyped target, info, AddrOf, elemType:
-      buildTyped target, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, typ)[1]:
-        buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-          copyTree target, tmp
-          target.addImmediateVal info, 1 # (len, p)-pair
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
-    # len:
-    target.addImmediateVal info, 1
-    buildTyped target, info, FieldAt, typeToIr(c.m, arrType):
-      copyTree target, tmp
-      target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
-
-  of tyArray:
-    let t = typeToIr(c.m, arrType)
-    target.addImmediateVal info, 0
-    buildTyped target, info, AddrOf, elemType:
-      buildTyped target, info, ArrayAt, t:
-        copyTree target, tmp
-        target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0
-    target.addImmediateVal info, 1
-    target.addIntVal(c.lit.numbers, info, c.m.nativeIntId, toInt lengthOrd(c.config, arrType))
-  else:
-    raiseAssert "addAddrOfFirstElem: " & typeToString(typ)
-
-proc genToOpenArrayConv(c: var ProcCon; arg: PNode; d: var Value; flags: GenFlags; destType: PType) =
-  let info = toLineInfo(c, arg.info)
-  let tmp = c.genx(arg, flags)
-  let arrType = destType.skipTypes(abstractVar)
-  template body(target) =
-    buildTyped target, info, ObjConstr, typeToIr(c.m, arrType):
-      c.addAddrOfFirstElem target, info, tmp, arg.typ
-
-  valueIntoDest c, info, d, arrType, body
-  freeTemp c, tmp
-
-proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: Opcode) =
-  let targetType = n.typ.skipTypes({tyDistinct})
-  let argType = arg.typ.skipTypes({tyDistinct})
-
-  if sameBackendType(targetType, argType) or (
-      argType.kind == tyProc and targetType.kind == argType.kind):
-    # don't do anything for lambda lifting conversions:
-    gen c, arg, d
-    return
-
-  if opc != Cast and targetType.skipTypes({tyVar, tyLent}).kind in {tyOpenArray, tyVarargs} and
-      argType.skipTypes({tyVar, tyLent}).kind notin {tyOpenArray, tyVarargs}:
-    genToOpenArrayConv c, arg, d, flags, n.typ
-    return
-
-  let info = toLineInfo(c, n.info)
-  let tmp = c.genx(arg, flags)
-  template body(target) =
-    buildTyped target, info, opc, typeToIr(c.m, n.typ):
-      if opc == CheckedObjConv:
-        target.addLabel info, CheckedGoto, c.exitLabel
-      copyTree target, tmp
-
-  valueIntoDest c, info, d, n.typ, body
-  freeTemp c, tmp
-
-proc genObjOrTupleConstr(c: var ProcCon; n: PNode; d: var Value; t: PType) =
-  # XXX x = (x.old, 22)  produces wrong code ... stupid self assignments
-  let info = toLineInfo(c, n.info)
-  template body(target) =
-    buildTyped target, info, ObjConstr, typeToIr(c.m, t):
-      for i in ord(n.kind == nkObjConstr)..<n.len:
-        let it = n[i]
-        if it.kind == nkExprColonExpr:
-          genField(c, it[0], Value target)
-          let tmp = c.genx(it[1])
-          copyTree target, tmp
-          c.freeTemp(tmp)
-        else:
-          let tmp = c.genx(it)
-          target.addImmediateVal info, i
-          copyTree target, tmp
-          c.freeTemp(tmp)
-
-      if isException(t):
-        target.addImmediateVal info, 1 # "name" field is at position after the "parent". See system.nim
-        target.addStrVal c.lit.strings, info, t.skipTypes(abstractInst).sym.name.s
-
-  constrIntoDest c, info, d, t, body
-
-proc genRefObjConstr(c: var ProcCon; n: PNode; d: var Value) =
-  if isEmpty(d): d = getTemp(c, n)
-  let info = toLineInfo(c, n.info)
-  let refType = n.typ.skipTypes(abstractInstOwned)
-  let objType = refType.elementType
-
-  rawGenNew(c, d, refType, n.info, needsInit = nfAllFieldsSet notin n.flags)
-  var deref = default(Value)
-  deref.buildTyped info, Load, typeToIr(c.m, objType):
-    deref.Tree.copyTree d
-  genObjOrTupleConstr c, n, deref, objType
-
-proc genSeqConstr(c: var ProcCon; n: PNode; d: var Value) =
-  if isEmpty(d): d = getTemp(c, n)
-
-  let info = toLineInfo(c, n.info)
-  let seqtype = skipTypes(n.typ, abstractVarRange)
-  let baseType = seqtype.elementType
-
-  var b = default(Value)
-  b.addIntVal c.lit.numbers, info, c.m.nativeIntId, n.len
-
-  genNewSeqPayload(c, info, d, b, seqtype)
-
-  for i in 0..<n.len:
-    var dd = default(Value)
-    buildTyped dd, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, seqtype)[1]:
-      buildTyped dd, info, FieldAt, typeToIr(c.m, seqtype):
-        copyTree Tree(dd), d
-        dd.addImmediateVal info, 1 # (len, p)-pair
-      dd.addIntVal c.lit.numbers, info, c.m.nativeIntId, i
-    gen(c, n[i], dd)
-
-  freeTemp c, d
-
-proc genArrayConstr(c: var ProcCon; n: PNode, d: var Value) =
-  let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
-  if seqType.kind == tySequence:
-    genSeqConstr(c, n, d)
-    return
-
-  let info = toLineInfo(c, n.info)
-  template body(target) =
-    buildTyped target, info, ArrayConstr, typeToIr(c.m, n.typ):
-      for i in 0..<n.len:
-        let tmp = c.genx(n[i])
-        copyTree target, tmp
-        c.freeTemp(tmp)
-
-  constrIntoDest c, info, d, n.typ, body
-
-proc genAsgn2(c: var ProcCon; a, b: PNode) =
-  assert a != nil
-  assert b != nil
-  var d = c.genx(a)
-  c.gen b, d
-
-proc irModule(c: var ProcCon; owner: PSym): string =
-  #if owner == c.m.module: "" else:
-  customPath(toFullPath(c.config, owner.info))
-
-proc fromForeignModule(c: ProcCon; s: PSym): bool {.inline.} =
-  result = ast.originatingModule(s) != c.m.module and not c.m.noModularity
-
-proc genForeignVar(c: var ProcCon; s: PSym) =
-  var opc: Opcode
-  if s.kind == skConst:
-    opc = SummonConst
-  elif sfThread in s.flags:
-    opc = SummonThreadLocal
-  else:
-    assert sfGlobal in s.flags
-    opc = SummonGlobal
-  let t = typeToIr(c.m, s.typ)
-  let info = toLineInfo(c, s.info)
-  build c.code, info, ForeignDecl:
-    buildTyped c.code, info, opc, t:
-      build c.code, info, ModuleSymUse:
-        c.code.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s))
-        c.code.addImmediateVal info, s.itemId.item.int
-
-proc genVarSection(c: var ProcCon; n: PNode) =
-  for a in n:
-    if a.kind == nkCommentStmt: continue
-    #assert(a[0].kind == nkSym) can happen for transformed vars
-    if a.kind == nkVarTuple:
-      c.gen(lowerTupleUnpacking(c.m.graph, a, c.m.idgen, c.prc))
-    else:
-      var vn = a[0]
-      if vn.kind == nkPragmaExpr: vn = vn[0]
-      if vn.kind == nkSym:
-        let s = vn.sym
-        if s.kind == skConst:
-          if dontInlineConstant(n, s.astdef):
-            let symId = toSymId(c, s)
-            c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s)
-            let val = c.genx(s.astdef)
-            let info = toLineInfo(c, a.info)
-            buildTyped c.code, info, SummonConst, typeToIr(c.m, s.typ):
-              c.code.addSymDef info, symId
-              c.code.copyTree val
-            freeTemp c, val
-        else:
-          var opc: Opcode
-          if sfThread in s.flags:
-            opc = SummonThreadLocal
-          elif sfGlobal in s.flags:
-            opc = SummonGlobal
-          else:
-            opc = Summon
-          #assert t.int >= 0, typeToString(s.typ) & (c.config $ n.info)
-          let symId = toSymId(c, s)
-          c.code.addSummon toLineInfo(c, a.info), symId, typeToIr(c.m, s.typ), opc
-          c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s)
-          if a[2].kind != nkEmpty:
-            genAsgn2(c, vn, a[2])
-      else:
-        if a[2].kind == nkEmpty:
-          genAsgn2(c, vn, expandDefault(vn.typ, vn.info))
-        else:
-          genAsgn2(c, vn, a[2])
-
-proc genAsgn(c: var ProcCon; n: PNode) =
-  var d = c.genx(n[0])
-  c.gen n[1], d
-
-proc convStrToCStr(c: var ProcCon; n: PNode; d: var Value) =
-  genUnaryCp(c, n, d, "nimToCStringConv", argAt = 0)
-
-proc convCStrToStr(c: var ProcCon; n: PNode; d: var Value) =
-  genUnaryCp(c, n, d, "cstrToNimstr", argAt = 0)
-
-proc genRdVar(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
-  let info = toLineInfo(c, n.info)
-  let s = n.sym
-  if fromForeignModule(c, s):
-    if s.kind in {skVar, skConst, skLet} and not c.m.pendingVarsAsSet.containsOrIncl(s.itemId):
-      c.m.pendingVars.add s
-
-    template body(target) =
-      build target, info, ModuleSymUse:
-        target.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s))
-        target.addImmediateVal info, s.itemId.item.int
-
-    valueIntoDest c, info, d, s.typ, body
-  else:
-    template body(target) =
-      target.addSymUse info, toSymId(c, s)
-    valueIntoDest c, info, d, s.typ, body
-
-proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) =
-  let s = n.sym
-  case s.kind
-  of skConst:
-    if dontInlineConstant(n, s.astdef):
-      genRdVar(c, n, d, flags)
-    else:
-      gen(c, s.astdef, d, flags)
-  of skVar, skForVar, skTemp, skLet, skResult, skParam:
-    genRdVar(c, n, d, flags)
-  of skProc, skFunc, skConverter, skMethod, skIterator:
-    if not c.m.noModularity:
-      # anon and generic procs have no AST so we need to remember not to forget
-      # to emit these:
-      if not c.m.processedProcs.contains(s.itemId):
-        if not c.m.pendingProcsAsSet.containsOrIncl(s.itemId):
-          c.m.pendingProcs.add s
-    genRdVar(c, n, d, flags)
-  of skEnumField:
-    let info = toLineInfo(c, n.info)
-    template body(target) =
-      target.addIntVal c.lit.numbers, info, typeToIr(c.m, n.typ), s.position
-    valueIntoDest c, info, d, n.typ, body
-  else:
-    localError(c.config, n.info, "cannot generate code for: " & s.name.s)
-
-proc genNumericLit(c: var ProcCon; n: PNode; d: var Value; bits: int64) =
-  let info = toLineInfo(c, n.info)
-  template body(target) =
-    target.addIntVal c.lit.numbers, info, typeToIr(c.m, n.typ), bits
-  valueIntoDest c, info, d, n.typ, body
-
-proc genStringLit(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  template body(target) =
-    target.addStrVal c.lit.strings, info, n.strVal
-  valueIntoDest c, info, d, n.typ, body
-
-proc genNilLit(c: var ProcCon; n: PNode; d: var Value) =
-  let info = toLineInfo(c, n.info)
-  template body(target) =
-    target.addNilVal info, typeToIr(c.m, n.typ)
-  valueIntoDest c, info, d, n.typ, body
-
-proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) =
-  if optRangeCheck in c.options:
-    let info = toLineInfo(c, n.info)
-    let tmp = c.genx n[0]
-    let a = c.genx n[1]
-    let b = c.genx n[2]
-    template body(target) =
-      buildTyped target, info, CheckedRange, typeToIr(c.m, n.typ):
-        target.addLabel info, CheckedGoto, c.exitLabel
-        copyTree target, tmp
-        copyTree target, a
-        copyTree target, b
-    valueIntoDest c, info, d, n.typ, body
-    freeTemp c, tmp
-    freeTemp c, a
-    freeTemp c, b
-  else:
-    gen c, n[0], d
-
-proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
-  let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc})
-  let arrayKind = arrayType.kind
-  let info = toLineInfo(c, n.info)
-  case arrayKind
-  of tyString:
-    let a = genx(c, n[0], flags)
-    let b = genIndexCheck(c, n[1], a, ForStr, arrayType)
-    let t = typeToIr(c.m, n.typ)
-    template body(target) =
-      buildTyped target, info, DerefArrayAt, c.m.strPayloadId[1]:
-        buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
-          copyTree target, a
-          target.addImmediateVal info, 1 # (len, p)-pair
-        copyTree target, b
-    intoDest d, info, t, body
-    freeTemp c, b
-    freeTemp c, a
-
-  of tyCstring, tyPtr, tyUncheckedArray:
-    let a = genx(c, n[0], flags)
-    let b = genx(c, n[1])
-    template body(target) =
-      buildTyped target, info, DerefArrayAt, typeToIr(c.m, arrayType):
-        copyTree target, a
-        copyTree target, b
-    valueIntoDest c, info, d, n.typ, body
-
-    freeTemp c, b
-    freeTemp c, a
-  of tyTuple:
-    let a = genx(c, n[0], flags)
-    let b = int n[1].intVal
-    template body(target) =
-      buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
-        copyTree target, a
-        target.addImmediateVal info, b
-    valueIntoDest c, info, d, n.typ, body
-
-    freeTemp c, a
-  of tyOpenArray, tyVarargs:
-    let a = genx(c, n[0], flags)
-    let b = genIndexCheck(c, n[1], a, ForOpenArray, arrayType)
-    let t = typeToIr(c.m, n.typ)
-    template body(target) =
-      buildTyped target, info, DerefArrayAt, openArrayPayloadType(c.m.types, c.m.nirm.types, n[0].typ):
-        buildTyped target, info, FieldAt, typeToIr(c.m, arrayType):
-          copyTree target, a
-          target.addImmediateVal info, 0 # (p, len)-pair
-        copyTree target, b
-    intoDest d, info, t, body
-
-    freeTemp c, b
-    freeTemp c, a
-  of tyArray:
-    let a = genx(c, n[0], flags)
-    var b = default(Value)
-    genIndex(c, n[1], n[0].typ, b)
-
-    template body(target) =
-      buildTyped target, info, ArrayAt, typeToIr(c.m, arrayType):
-        copyTree target, a
-        copyTree target, b
-    valueIntoDest c, info, d, n.typ, body
-    freeTemp c, b
-    freeTemp c, a
-  of tySequence:
-    let a = genx(c, n[0], flags)
-    let b = genIndexCheck(c, n[1], a, ForSeq, arrayType)
-    let t = typeToIr(c.m, n.typ)
-    template body(target) =
-      buildTyped target, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, n[0].typ)[1]:
-        buildTyped target, info, FieldAt, t:
-          copyTree target, a
-          target.addImmediateVal info, 1 # (len, p)-pair
-        copyTree target, b
-    intoDest d, info, t, body
-    freeTemp c, b
-    freeTemp c, a
-  else:
-    localError c.config, n.info, "invalid type for nkBracketExpr: " & $arrayKind
-
-proc genObjAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
-  let info = toLineInfo(c, n.info)
-
-  var n0 = n[0]
-  var opc = FieldAt
-  if n0.kind == nkDotExpr:
-    # obj[].a --> DerefFieldAt instead of FieldAt:
-    n0 = n[0]
-    opc = DerefFieldAt
-
-  let a = genx(c, n0, flags)
-
-  template body(target) =
-    buildTyped target, info, opc, typeToIr(c.m, n0.typ):
-      copyTree target, a
-      genField c, n[1], Value(target)
-
-  valueIntoDest c, info, d, n.typ, body
-  freeTemp c, a
-
-proc genParams(c: var ProcCon; params: PNode; prc: PSym): PSym =
-  result = nil
-  if params.len > 0 and resultPos < prc.ast.len:
-    let resNode = prc.ast[resultPos]
-    result = resNode.sym # get result symbol
-    c.code.addSummon toLineInfo(c, result.info), toSymId(c, result),
-      typeToIr(c.m, result.typ), SummonResult
-  elif prc.typ.len > 0 and not isEmptyType(prc.typ.returnType) and not isCompileTimeOnly(prc.typ.returnType):
-    # happens for procs without bodies:
-    let t = typeToIr(c.m, prc.typ.returnType)
-    let tmp = allocTemp(c, t)
-    c.code.addSummon toLineInfo(c, params.info), tmp, t, SummonResult
-
-  for i in 1..<params.len:
-    let s = params[i].sym
-    if not isCompileTimeOnly(s.typ):
-      let t = typeToIr(c.m, s.typ)
-      assert t.int != -1, typeToString(s.typ)
-      let symId = toSymId(c, s)
-      c.code.addSummon toLineInfo(c, params[i].info), symId, t, SummonParam
-      c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s)
-
-proc addCallConv(c: var ProcCon; info: PackedLineInfo; callConv: TCallingConvention) =
-  template ann(s: untyped) = c.code.addPragmaId info, s
-  case callConv
-  of ccNimCall, ccFastCall, ccClosure: ann FastCall
-  of ccStdCall: ann StdCall
-  of ccCDecl: ann CDeclCall
-  of ccSafeCall: ann SafeCall
-  of ccSysCall: ann SysCall
-  of ccInline: ann InlineCall
-  of ccNoInline: ann NoinlineCall
-  of ccThisCall: ann ThisCall
-  of ccNoConvention, ccMember: ann NoCall
-
-proc genProc(cOuter: var ProcCon; prc: PSym) =
-  if prc.magic notin generatedMagics: return
-  if cOuter.m.processedProcs.containsOrIncl(prc.itemId):
-    return
-  #assert cOuter.m.inProc == 0, " in nested proc! " & prc.name.s
-  if cOuter.m.inProc > 0:
-    if not cOuter.m.pendingProcsAsSet.containsOrIncl(prc.itemId):
-      cOuter.m.pendingProcs.add prc
-    return
-  inc cOuter.m.inProc
-
-  var c = initProcCon(cOuter.m, prc, cOuter.m.graph.config)
-  let body =
-    if not fromForeignModule(c, prc):
-      transformBody(c.m.graph, c.m.idgen, prc, {useCache, keepOpenArrayConversions})
-    else:
-      nil
-
-  let info = toLineInfo(c, prc.info)
-  build c.code, info, (if body != nil: ProcDecl else: ForeignProcDecl):
-    if body != nil:
-      let symId = toSymId(c, prc)
-      addSymDef c.code, info, symId
-      c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(prc.name.s)
-    else:
-      build c.code, info, ModuleSymUse:
-        c.code.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(prc))
-        c.code.addImmediateVal info, prc.itemId.item.int
-    addCallConv c, info, prc.typ.callConv
-    if sfCompilerProc in prc.flags:
-      build c.code, info, PragmaPair:
-        c.code.addPragmaId info, CoreName
-        c.code.addStrVal c.lit.strings, info, prc.name.s
-    if {sfImportc, sfExportc} * prc.flags != {}:
-      build c.code, info, PragmaPair:
-        c.code.addPragmaId info, ExternName
-        c.code.addStrVal c.lit.strings, info, prc.loc.r
-      if sfImportc in prc.flags:
-        if lfHeader in prc. loc.flags:
-          assert(prc. annex != nil)
-          let str = getStr(prc. annex.path)
-          build c.code, info, PragmaPair:
-            c.code.addPragmaId info, HeaderImport
-            c.code.addStrVal c.lit.strings, info, str
-        elif lfDynamicLib in prc. loc.flags:
-          assert(prc. annex != nil)
-          let str = getStr(prc. annex.path)
-          build c.code, info, PragmaPair:
-            c.code.addPragmaId info, DllImport
-            c.code.addStrVal c.lit.strings, info, str
-      elif sfExportc in prc.flags:
-        if lfDynamicLib in prc. loc.flags:
-          c.code.addPragmaId info, DllExport
-        else:
-          c.code.addPragmaId info, ObjExport
-
-    let resultSym = genParams(c, prc.typ.n, prc)
-    if body != nil:
-      gen(c, body)
-      patch c, body, c.exitLabel
-      if resultSym != nil:
-        build c.code, info, Ret:
-          c.code.addSymUse info, toSymId(c, resultSym)
-      else:
-        build c.code, info, Ret:
-          c.code.addNop info
-
-  #copyTree cOuter.code, c.code
-  dec cOuter.m.inProc
-
-proc genProc(cOuter: var ProcCon; n: PNode) =
-  if n.len == 0 or n[namePos].kind != nkSym: return
-  let prc = n[namePos].sym
-  if isGenericRoutineStrict(prc) or isCompileTimeProc(prc) or sfForward in prc.flags: return
-  genProc cOuter, prc
-
-proc genClosureCall(c: var ProcCon; n: PNode; d: var Value) =
-  let typ = skipTypes(n[0].typ, abstractInstOwned)
-  if tfIterator in typ.flags:
-    const PatIter = "$1.ClP_0($3, $1.ClE_0)" # we know the env exists
-
-  else:
-    const PatProc = "$1.ClE_0? $1.ClP_0($3, $1.ClE_0):(($4)($1.ClP_0))($2)"
-
-
-proc genComplexCall(c: var ProcCon; n: PNode; d: var Value) =
-  if n[0].typ != nil and n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
-    # XXX genClosureCall p, n, d
-    genCall c, n, d
-  else:
-    genCall c, n, d
-
-proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) =
-  when defined(nimCompilerStacktraceHints):
-    setFrameMsg c.config$n.info & " " & $n.kind & " " & $flags
-  case n.kind
-  of nkSym: genSym(c, n, d, flags)
-  of nkCallKinds:
-    if n[0].kind == nkSym:
-      let s = n[0].sym
-      if s.magic != mNone:
-        genMagic(c, n, d, s.magic)
-      elif s.kind == skMethod:
-        localError(c.config, n.info, "cannot call method " & s.name.s &
-          " at compile time")
-      else:
-        genComplexCall(c, n, d)
-    else:
-      genComplexCall(c, n, d)
-  of nkCharLit..nkInt64Lit, nkUIntLit..nkUInt64Lit:
-    genNumericLit(c, n, d, n.intVal)
-  of nkFloatLit..nkFloat128Lit:
-    genNumericLit(c, n, d, cast[int64](n.floatVal))
-  of nkStrLit..nkTripleStrLit:
-    genStringLit(c, n, d)
-  of nkNilLit:
-    if not n.typ.isEmptyType: genNilLit(c, n, d)
-    else: unused(c, n, d)
-  of nkAsgn, nkFastAsgn, nkSinkAsgn:
-    unused(c, n, d)
-    genAsgn(c, n)
-  of nkDotExpr: genObjAccess(c, n, d, flags)
-  of nkCheckedFieldExpr: genObjAccess(c, n[0], d, flags)
-  of nkBracketExpr: genArrAccess(c, n, d, flags)
-  of nkDerefExpr, nkHiddenDeref: genDeref(c, n, d, flags)
-  of nkAddr, nkHiddenAddr: genAddr(c, n, d, flags)
-  of nkIfStmt, nkIfExpr: genIf(c, n, d)
-  of nkWhenStmt:
-    # This is "when nimvm" node. Chose the first branch.
-    gen(c, n[0][1], d)
-  of nkCaseStmt: genCase(c, n, d)
-  of nkWhileStmt:
-    unused(c, n, d)
-    genWhile(c, n)
-  of nkBlockExpr, nkBlockStmt: genBlock(c, n, d)
-  of nkReturnStmt: genReturn(c, n)
-  of nkRaiseStmt: genRaise(c, n)
-  of nkBreakStmt: genBreak(c, n)
-  of nkTryStmt, nkHiddenTryStmt: genTry(c, n, d)
-  of nkStmtList:
-    #unused(c, n, d)
-    # XXX Fix this bug properly, lexim triggers it
-    for x in n: gen(c, x)
-  of nkStmtListExpr:
-    for i in 0..<n.len-1: gen(c, n[i])
-    gen(c, n[^1], d, flags)
-  of nkPragmaBlock:
-    gen(c, n.lastSon, d, flags)
-  of nkDiscardStmt:
-    unused(c, n, d)
-    gen(c, n[0], d)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    genConv(c, n, n[1], d, flags, NumberConv) # misnomer?
-  of nkObjDownConv:
-    genConv(c, n, n[0], d, flags, ObjConv)
-  of nkObjUpConv:
-    genConv(c, n, n[0], d, flags, CheckedObjConv)
-  of nkVarSection, nkLetSection, nkConstSection:
-    unused(c, n, d)
-    genVarSection(c, n)
-  of nkLambdaKinds:
-    #let s = n[namePos].sym
-    #discard genProc(c, s)
-    gen(c, newSymNode(n[namePos].sym), d)
-  of nkChckRangeF, nkChckRange64, nkChckRange:
-    genRangeCheck(c, n, d)
-  of declarativeDefs - {nkIteratorDef}:
-    unused(c, n, d)
-    genProc(c, n)
-  of nkEmpty, nkCommentStmt, nkTypeSection, nkPragma,
-     nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt,
-     nkMixinStmt, nkBindStmt, nkMacroDef, nkIteratorDef:
-    unused(c, n, d)
-  of nkStringToCString: convStrToCStr(c, n, d)
-  of nkCStringToString: convCStrToStr(c, n, d)
-  of nkBracket: genArrayConstr(c, n, d)
-  of nkCurly: genSetConstr(c, n, d)
-  of nkObjConstr:
-    if n.typ.skipTypes(abstractInstOwned).kind == tyRef:
-      genRefObjConstr(c, n, d)
-    else:
-      genObjOrTupleConstr(c, n, d, n.typ)
-  of nkPar, nkClosure, nkTupleConstr:
-    genObjOrTupleConstr(c, n, d, n.typ)
-  of nkCast:
-    genConv(c, n, n[1], d, flags, Cast)
-  of nkComesFrom:
-    discard "XXX to implement for better stack traces"
-  #of nkState: genState(c, n)
-  #of nkGotoState: genGotoState(c, n)
-  #of nkBreakState: genBreakState(c, n, d)
-  else:
-    localError(c.config, n.info, "cannot generate IR code for " & $n)
-
-proc genPendingProcs(c: var ProcCon) =
-  while c.m.pendingProcs.len > 0 or c.m.pendingVars.len > 0:
-    let procs = move(c.m.pendingProcs)
-    for v in procs:
-      genProc(c, v)
-    let vars = move(c.m.pendingVars)
-    for v in vars:
-      genForeignVar(c, v)
-
-proc genStmt*(c: var ProcCon; n: PNode): NodePos =
-  result = NodePos c.code.len
-  var d = default(Value)
-  c.gen(n, d)
-  unused c, n, d
-  genPendingProcs c
-
-proc genExpr*(c: var ProcCon; n: PNode, requiresValue = true): int =
-  result = c.code.len
-  var d = default(Value)
-  c.gen(n, d)
-  genPendingProcs c
-  if isEmpty d:
-    if requiresValue:
-      globalError(c.config, n.info, "VM problem: d register is not set")
diff --git a/compiler/nir/cir.nim b/compiler/nir/cir.nim
deleted file mode 100644
index 01f9c4c9a..000000000
--- a/compiler/nir/cir.nim
+++ /dev/null
@@ -1,983 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-# We produce C code as a list of tokens.
-
-import std / [assertions, syncio, tables, intsets, formatfloat]
-from std / strutils import toOctal
-import .. / ic / [bitabs, rodfiles]
-import nirtypes, nirinsts, nirfiles
-import ../../dist/checksums/src/checksums/md5
-
-type
-  Token = LitId # indexing into the tokens BiTable[string]
-
-  PredefinedToken = enum
-    IgnoreMe = "<unused>"
-    EmptyToken = ""
-    CurlyLe = "{"
-    CurlyRi = "}"
-    ParLe = "("
-    ParRi = ")"
-    BracketLe = "["
-    BracketRi = "]"
-    NewLine = "\n"
-    Semicolon = ";"
-    Comma = ", "
-    Space = " "
-    Colon = ": "
-    Dot = "."
-    Arrow = "->"
-    Star = "*"
-    Amp = "&"
-    AsgnOpr = " = "
-    ScopeOpr = "::"
-    ConstKeyword = "const "
-    StaticKeyword = "static "
-    ExternKeyword = "extern "
-    WhileKeyword = "while "
-    IfKeyword = "if ("
-    ElseKeyword = "else "
-    SwitchKeyword = "switch "
-    CaseKeyword = "case "
-    DefaultKeyword = "default:"
-    BreakKeyword = "break"
-    NullPtr = "nullptr"
-    IfNot = "if (!("
-    ReturnKeyword = "return "
-    TypedefStruct = "typedef struct "
-    TypedefUnion = "typedef union "
-    IncludeKeyword = "#include "
-
-proc fillTokenTable(tab: var BiTable[string]) =
-  for e in EmptyToken..high(PredefinedToken):
-    let id = tab.getOrIncl $e
-    assert id == LitId(e), $(id, " ", ord(e))
-
-type
-  GeneratedCode* = object
-    m: NirModule
-    includes: seq[LitId]
-    includedHeaders: IntSet
-    data: seq[LitId]
-    protos: seq[LitId]
-    code: seq[LitId]
-    init: seq[LitId]
-    tokens: BiTable[string]
-    emittedStrings: IntSet
-    needsPrefix: IntSet
-    generatedTypes: IntSet
-    mangledModules: Table[LitId, LitId]
-
-proc initGeneratedCode*(m: sink NirModule): GeneratedCode =
-  result = GeneratedCode(m: m, code: @[], tokens: initBiTable[string]())
-  fillTokenTable(result.tokens)
-
-proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} =
-  g.code.add Token(t)
-
-proc add*(g: var GeneratedCode; s: string) {.inline.} =
-  g.code.add g.tokens.getOrIncl(s)
-
-proc mangleModuleName(c: var GeneratedCode; key: LitId): LitId =
-  result = c.mangledModules.getOrDefault(key, LitId(0))
-  if result == LitId(0):
-    let u {.cursor.} = c.m.lit.strings[key]
-    var last = u.len - len(".nim") - 1
-    var start = last
-    while start >= 0 and u[start] != '/': dec start
-    var sum = getMD5(u)
-    sum.setLen(8)
-    let dest = u.substr(start+1, last) & sum
-    result = c.tokens.getOrIncl(dest)
-    c.mangledModules[key] = result
-
-type
-  CppFile = object
-    f: File
-
-proc write(f: var CppFile; s: string) = write(f.f, s)
-proc write(f: var CppFile; c: char) = write(f.f, c)
-
-proc writeTokenSeq(f: var CppFile; s: seq[Token]; c: GeneratedCode) =
-  var indent = 0
-  for i in 0..<s.len:
-    let x = s[i]
-    case x
-    of Token(CurlyLe):
-      inc indent
-      write f, c.tokens[x]
-      write f, "\n"
-      for i in 1..indent*2: write f, ' '
-    of Token(CurlyRi):
-      dec indent
-      write f, c.tokens[x]
-      if i+1 < s.len and s[i+1] == Token(CurlyRi):
-        discard
-      else:
-        write f, "\n"
-        for i in 1..indent*2: write f, ' '
-    of Token(Semicolon):
-      write f, c.tokens[x]
-      if i+1 < s.len and s[i+1] == Token(CurlyRi):
-        discard "no newline before }"
-      else:
-        write f, "\n"
-        for i in 1..indent*2: write f, ' '
-    of Token(NewLine):
-      write f, c.tokens[x]
-      for i in 1..indent*2: write f, ' '
-    else:
-      write f, c.tokens[x]
-
-
-# Type graph
-
-type
-  TypeList = object
-    processed: IntSet
-    s: seq[(TypeId, PredefinedToken)]
-
-proc add(dest: var TypeList; elem: TypeId; decl: PredefinedToken) =
-  if not containsOrIncl(dest.processed, int(elem)):
-    dest.s.add (elem, decl)
-
-type
-  TypeOrder = object
-    forwardedDecls, ordered: TypeList
-    typeImpls: Table[string, TypeId]
-    lookedAt: IntSet
-
-proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId)
-
-proc recordDependency(types: TypeGraph; lit: Literals; c: var TypeOrder; parent, child: TypeId) =
-  var ch = child
-  var viaPointer = false
-  while true:
-    case types[ch].kind
-    of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy:
-      viaPointer = true
-      ch = elementType(types, ch)
-    of LastArrayTy:
-      ch = elementType(types, ch)
-    else:
-      break
-
-  case types[ch].kind
-  of ObjectTy, UnionTy:
-    let decl = if types[ch].kind == ObjectTy: TypedefStruct else: TypedefUnion
-    let obj = c.typeImpls.getOrDefault(lit.strings[types[ch].litId])
-    if viaPointer:
-      c.forwardedDecls.add obj, decl
-    else:
-      if not containsOrIncl(c.lookedAt, obj.int):
-        traverseObject(types, lit, c, obj)
-      c.ordered.add obj, decl
-  of ArrayTy:
-    if viaPointer:
-      c.forwardedDecls.add ch, TypedefStruct
-    else:
-      if not containsOrIncl(c.lookedAt, ch.int):
-        traverseObject(types, lit, c, ch)
-      c.ordered.add ch, TypedefStruct
-  else:
-    discard "uninteresting type as we only focus on the required struct declarations"
-
-proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId) =
-  for x in sons(types, t):
-    case types[x].kind
-    of FieldDecl:
-      recordDependency types, lit, c, t, x.firstSon
-    of ObjectTy:
-      # inheritance
-      recordDependency types, lit, c, t, x
-    else: discard
-
-proc traverseTypes(types: TypeGraph; lit: Literals; c: var TypeOrder) =
-  for t in allTypes(types):
-    if types[t].kind in {ObjectDecl, UnionDecl}:
-      assert types[t.firstSon].kind == NameVal
-      c.typeImpls[lit.strings[types[t.firstSon].litId]] = t
-
-  for t in allTypesIncludingInner(types):
-    case types[t].kind
-    of ObjectDecl, UnionDecl:
-      traverseObject types, lit, c, t
-      let decl = if types[t].kind == ObjectDecl: TypedefStruct else: TypedefUnion
-      c.ordered.add t, decl
-    of ArrayTy:
-      traverseObject types, lit, c, t
-      c.ordered.add t, TypedefStruct
-    else: discard
-
-when false:
-  template emitType(s: string) = c.types.add c.tokens.getOrIncl(s)
-  template emitType(t: Token) = c.types.add t
-  template emitType(t: PredefinedToken) = c.types.add Token(t)
-
-proc genType(g: var GeneratedCode; types: TypeGraph; lit: Literals; t: TypeId; name = "") =
-  template maybeAddName =
-    if name != "":
-      g.add Space
-      g.add name
-
-  template atom(s: string) =
-    g.add s
-    maybeAddName()
-  case types[t].kind
-  of VoidTy: atom "void"
-  of IntTy: atom "NI" & $types[t].integralBits
-  of UIntTy: atom "NU" & $types[t].integralBits
-  of FloatTy: atom "NF" & $types[t].integralBits
-  of BoolTy: atom "NB" & $types[t].integralBits
-  of CharTy: atom "NC" & $types[t].integralBits
-  of ObjectTy, UnionTy, NameVal, AnnotationVal:
-    atom lit.strings[types[t].litId]
-  of VarargsTy:
-    g.add "..."
-  of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy:
-    genType g, types, lit, elementType(types, t)
-    g.add Star
-    maybeAddName()
-  of ArrayTy:
-    genType g, types, lit, arrayName(types, t)
-    maybeAddName()
-  of LastArrayTy:
-    genType g, types, lit, elementType(types, t)
-    maybeAddName()
-    g.add BracketLe
-    g.add BracketRi
-  of ProcTy:
-    let (retType, callConv) = returnType(types, t)
-    genType g, types, lit, retType
-    g.add Space
-    g.add ParLe
-    genType g, types, lit, callConv
-    g.add Star # "(*fn)"
-    maybeAddName()
-    g.add ParRi
-    g.add ParLe
-    var i = 0
-    for ch in params(types, t):
-      if i > 0: g.add Comma
-      genType g, types, lit, ch
-      inc i
-    g.add ParRi
-  of ObjectDecl, UnionDecl:
-    atom lit.strings[types[t.firstSon].litId]
-  of IntVal, SizeVal, AlignVal, OffsetVal, FieldDecl:
-    #raiseAssert "did not expect: " & $types[t].kind
-    g.add "BUG "
-    atom $types[t].kind
-
-proc generateTypes(g: var GeneratedCode; types: TypeGraph; lit: Literals; c: TypeOrder) =
-  for (t, declKeyword) in c.forwardedDecls.s:
-    let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon
-    let s {.cursor.} = lit.strings[types[name].litId]
-    g.add declKeyword
-    g.add s
-    g.add Space
-    g.add s
-    g.add Semicolon
-
-  for (t, declKeyword) in c.ordered.s:
-    let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon
-    let litId = types[name].litId
-    if not g.generatedTypes.containsOrIncl(litId.int):
-      let s {.cursor.} = lit.strings[litId]
-      g.add declKeyword
-      g.add CurlyLe
-      if types[t].kind == ArrayTy:
-        genType g, types, lit, elementType(types, t), "a"
-        g.add BracketLe
-        g.add $arrayLen(types, t)
-        g.add BracketRi
-        g.add Semicolon
-      else:
-        var i = 0
-        for x in sons(types, t):
-          case types[x].kind
-          of FieldDecl:
-            genType g, types, lit, x.firstSon, "F" & $i
-            g.add Semicolon
-            inc i
-          of ObjectTy:
-            genType g, types, lit, x, "P"
-            g.add Semicolon
-          else: discard
-      g.add CurlyRi
-      g.add s
-      g.add Semicolon
-
-# Procs
-
-proc toCChar*(c: char; result: var string) {.inline.} =
-  case c
-  of '\0'..'\x1F', '\x7F'..'\xFF':
-    result.add '\\'
-    result.add toOctal(c)
-  of '\'', '\"', '\\', '?':
-    result.add '\\'
-    result.add c
-  else:
-    result.add c
-
-proc makeCString(s: string): string =
-  result = newStringOfCap(s.len + 10)
-  result.add('"')
-  for c in s: toCChar(c, result)
-  result.add('"')
-
-template emitData(s: string) = c.data.add c.tokens.getOrIncl(s)
-template emitData(t: Token) = c.data.add t
-template emitData(t: PredefinedToken) = c.data.add Token(t)
-
-proc genStrLit(c: var GeneratedCode; lit: Literals; litId: LitId): Token =
-  result = Token(c.tokens.getOrIncl "QStr" & $litId)
-  if not containsOrIncl(c.emittedStrings, int(litId)):
-    let s {.cursor.} = lit.strings[litId]
-    emitData "static const struct "
-    emitData CurlyLe
-    emitData "NI cap"
-    emitData Semicolon
-    emitData "NC8 data"
-    emitData BracketLe
-    emitData $s.len
-    emitData "+1"
-    emitData BracketRi
-    emitData Semicolon
-    emitData CurlyRi
-    emitData result
-    emitData AsgnOpr
-    emitData CurlyLe
-    emitData $s.len
-    emitData " | NIM_STRLIT_FLAG"
-    emitData Comma
-    emitData makeCString(s)
-    emitData CurlyRi
-    emitData Semicolon
-
-proc genIntLit(c: var GeneratedCode; lit: Literals; litId: LitId) =
-  let i = lit.numbers[litId]
-  if i > low(int32) and i <= high(int32):
-    c.add $i
-  elif i == low(int32):
-    # Nim has the same bug for the same reasons :-)
-    c.add "(-2147483647 -1)"
-  elif i > low(int64):
-    c.add "IL64("
-    c.add $i
-    c.add ")"
-  else:
-    c.add "(IL64(-9223372036854775807) - IL64(1))"
-
-proc gen(c: var GeneratedCode; t: Tree; n: NodePos)
-
-proc genDisplayName(c: var GeneratedCode; symId: SymId) =
-  let displayName = c.m.symnames[symId]
-  if displayName != LitId(0):
-    c.add "/*"
-    c.add c.m.lit.strings[displayName]
-    c.add "*/"
-
-proc genSymDef(c: var GeneratedCode; t: Tree; n: NodePos) =
-  if t[n].kind == SymDef:
-    let symId = t[n].symId
-    c.needsPrefix.incl symId.int
-    genDisplayName c, symId
-  gen c, t, n
-
-proc genGlobal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) =
-  c.add annotation
-  let m: string
-  if t[name].kind == SymDef:
-    let symId = t[name].symId
-    m = c.tokens[mangleModuleName(c, c.m.namespace)] & "__" & $symId
-    genDisplayName c, symId
-  else:
-    assert t[name].kind == ModuleSymUse
-    let (x, y) = sons2(t, name)
-    m = c.tokens[mangleModuleName(c, t[x].litId)] & "__" & $t[y].immediateVal
-  genType c, c.m.types, c.m.lit, t[typ].typeId, m
-
-proc genLocal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) =
-  assert t[name].kind == SymDef
-  c.add annotation
-  let symId = t[name].symId
-  genType c, c.m.types, c.m.lit, t[typ].typeId, "q" & $symId
-  genDisplayName c, symId
-
-proc genProcDecl(c: var GeneratedCode; t: Tree; n: NodePos; isExtern: bool) =
-  let signatureBegin = c.code.len
-  let name = n.firstSon
-
-  var prc = n.firstSon
-  next t, prc
-
-  while true:
-    case t[prc].kind
-    of PragmaPair:
-      let (x, y) = sons2(t, prc)
-      let key = cast[PragmaKey](t[x].rawOperand)
-      case key
-      of HeaderImport:
-        let lit = t[y].litId
-        let headerAsStr {.cursor.} = c.m.lit.strings[lit]
-        let header = c.tokens.getOrIncl(headerAsStr)
-        # headerAsStr can be empty, this has the semantics of the `nodecl` pragma:
-        if headerAsStr.len > 0 and not c.includedHeaders.containsOrIncl(int header):
-          if headerAsStr[0] == '#':
-            discard "skip the #include"
-          else:
-            c.includes.add Token(IncludeKeyword)
-          c.includes.add header
-          c.includes.add Token NewLine
-        # do not generate code for importc'ed procs:
-        return
-      of DllImport:
-        let lit = t[y].litId
-        raiseAssert "cannot eval: " & c.m.lit.strings[lit]
-      else: discard
-    of PragmaId: discard
-    else: break
-    next t, prc
-
-  var resultDeclPos = NodePos(-1)
-  if t[prc].kind == SummonResult:
-    resultDeclPos = prc
-    gen c, t, prc.firstSon
-    next t, prc
-  else:
-    c.add "void"
-  c.add Space
-  genSymDef c, t, name
-  c.add ParLe
-  var params = 0
-  while t[prc].kind == SummonParam:
-    if params > 0: c.add Comma
-    let (typ, sym) = sons2(t, prc)
-    genLocal c, t, sym, typ, ""
-    next t, prc
-    inc params
-  if params == 0:
-    c.add "void"
-  c.add ParRi
-
-  for i in signatureBegin ..< c.code.len:
-    c.protos.add c.code[i]
-  c.protos.add Token Semicolon
-
-  if isExtern:
-    c.code.setLen signatureBegin
-  else:
-    c.add CurlyLe
-    if resultDeclPos.int >= 0:
-      gen c, t, resultDeclPos
-    for ch in sonsRest(t, n, prc):
-      gen c, t, ch
-    c.add CurlyRi
-
-template triop(opr) =
-  let (typ, a, b) = sons3(t, n)
-  c.add ParLe
-  c.add ParLe
-  gen c, t, typ
-  c.add ParRi
-  gen c, t, a
-  c.add opr
-  gen c, t, b
-  c.add ParRi
-
-template cmpop(opr) =
-  let (_, a, b) = sons3(t, n)
-  c.add ParLe
-  gen c, t, a
-  c.add opr
-  gen c, t, b
-  c.add ParRi
-
-template binaryop(opr) =
-  let (typ, a) = sons2(t, n)
-  c.add ParLe
-  c.add ParLe
-  gen c, t, typ
-  c.add ParRi
-  c.add opr
-  gen c, t, a
-  c.add ParRi
-
-template checkedBinaryop(opr) =
-  let (typ, labIdx, a, b) = sons4(t, n)
-  let bits = integralBits(c.m.types[t[typ].typeId])
-  let lab = t[labIdx].label
-
-  c.add (opr & $bits)
-  c.add ParLe
-  c.gen t, a
-  c.add Comma
-  c.gen t, b
-  c.add Comma
-  c.add "L" & $lab.int
-  c.add ParRi
-
-proc genNumberConv(c: var GeneratedCode; t: Tree; n: NodePos) =
-  let (typ, arg) = sons2(t, n)
-  if t[arg].kind == IntVal:
-    let litId = t[arg].litId
-    c.add ParLe
-    c.add ParLe
-    gen c, t, typ
-    c.add ParRi
-    case c.m.types[t[typ].typeId].kind
-    of UIntTy:
-      let x = cast[uint64](c.m.lit.numbers[litId])
-      c.add $x
-    of FloatTy:
-      let x = cast[float64](c.m.lit.numbers[litId])
-      c.add $x
-    else:
-      gen c, t, arg
-    c.add ParRi
-  else:
-    binaryop ""
-
-template moveToDataSection(body: untyped) =
-  let oldLen = c.code.len
-  body
-  for i in oldLen ..< c.code.len:
-    c.data.add c.code[i]
-  setLen c.code, oldLen
-
-proc gen(c: var GeneratedCode; t: Tree; n: NodePos) =
-  case t[n].kind
-  of Nop:
-    discard "nothing to emit"
-  of ImmediateVal:
-    c.add $t[n].immediateVal
-  of IntVal:
-    genIntLit c, c.m.lit, t[n].litId
-  of StrVal:
-    c.code.add genStrLit(c, c.m.lit, t[n].litId)
-  of Typed:
-    genType c, c.m.types, c.m.lit, t[n].typeId
-  of SymDef, SymUse:
-    let s = t[n].symId
-    if c.needsPrefix.contains(s.int):
-      c.code.add mangleModuleName(c, c.m.namespace)
-      c.add "__"
-      c.add $s
-    else:
-      # XXX Use proper names here
-      c.add "q"
-      c.add $s
-
-  of ModuleSymUse:
-    let (x, y) = sons2(t, n)
-    let u = mangleModuleName(c, t[x].litId)
-    let s = t[y].immediateVal
-    c.code.add u
-    c.add "__"
-    c.add $s
-
-  of NilVal:
-    c.add NullPtr
-  of LoopLabel:
-    c.add WhileKeyword
-    c.add ParLe
-    c.add "1"
-    c.add ParRi
-    c.add CurlyLe
-  of GotoLoop:
-    c.add CurlyRi
-  of Label:
-    let lab = t[n].label
-    c.add "L"
-    c.add $lab.int
-    c.add Colon
-    c.add Semicolon
-  of Goto:
-    let lab = t[n].label
-    c.add "goto L"
-    c.add $lab.int
-    c.add Semicolon
-  of CheckedGoto:
-    discard "XXX todo"
-  of ArrayConstr:
-    c.add CurlyLe
-    c.add ".a = "
-    c.add CurlyLe
-    var i = 0
-    for ch in sonsFrom1(t, n):
-      if i > 0: c.add Comma
-      c.gen t, ch
-      inc i
-    c.add CurlyRi
-    c.add CurlyRi
-  of ObjConstr:
-    c.add CurlyLe
-    var i = 0
-    for ch in sonsFrom1(t, n):
-      if i mod 2 == 0:
-        if i > 0: c.add Comma
-        c.add ".F" & $t[ch].immediateVal
-        c.add AsgnOpr
-      else:
-        c.gen t, ch
-      inc i
-    c.add CurlyRi
-  of Ret:
-    c.add ReturnKeyword
-    c.gen t, n.firstSon
-    c.add Semicolon
-  of Select:
-    c.add SwitchKeyword
-    c.add ParLe
-    let (_, selector) = sons2(t, n)
-    c.gen t, selector
-    c.add ParRi
-    c.add CurlyLe
-    for ch in sonsFromN(t, n, 2):
-      c.gen t, ch
-    c.add CurlyRi
-  of SelectPair:
-    let (le, ri) = sons2(t, n)
-    c.gen t, le
-    c.gen t, ri
-  of SelectList:
-    for ch in sons(t, n):
-      c.gen t, ch
-  of SelectValue:
-    c.add CaseKeyword
-    c.gen t, n.firstSon
-    c.add Colon
-  of SelectRange:
-    let (le, ri) = sons2(t, n)
-    c.add CaseKeyword
-    c.gen t, le
-    c.add " ... "
-    c.gen t, ri
-    c.add Colon
-  of ForeignDecl:
-    c.data.add LitId(ExternKeyword)
-    c.gen t, n.firstSon
-  of SummonGlobal:
-    moveToDataSection:
-      let (typ, sym) = sons2(t, n)
-      c.genGlobal t, sym, typ, ""
-      c.add Semicolon
-  of SummonThreadLocal:
-    moveToDataSection:
-      let (typ, sym) = sons2(t, n)
-      c.genGlobal t, sym, typ, "__thread "
-      c.add Semicolon
-  of SummonConst:
-    moveToDataSection:
-      let (typ, sym, val) = sons3(t, n)
-      c.genGlobal t, sym, typ, "const "
-      c.add AsgnOpr
-      c.gen t, val
-      c.add Semicolon
-  of Summon, SummonResult:
-    let (typ, sym) = sons2(t, n)
-    c.genLocal t, sym, typ, ""
-    c.add Semicolon
-
-  of SummonParam:
-    raiseAssert "SummonParam should have been handled in genProc"
-  of Kill:
-    discard "we don't care about Kill instructions"
-  of AddrOf:
-    let (_, arg) = sons2(t, n)
-    c.add "&"
-    gen c, t, arg
-  of DerefArrayAt:
-    let (_, a, i) = sons3(t, n)
-    gen c, t, a
-    c.add BracketLe
-    gen c, t, i
-    c.add BracketRi
-  of ArrayAt:
-    let (_, a, i) = sons3(t, n)
-    gen c, t, a
-    c.add Dot
-    c.add "a"
-    c.add BracketLe
-    gen c, t, i
-    c.add BracketRi
-  of FieldAt:
-    let (_, a, b) = sons3(t, n)
-    gen c, t, a
-    let field = t[b].immediateVal
-    c.add Dot
-    c.add "F" & $field
-  of DerefFieldAt:
-    let (_, a, b) = sons3(t, n)
-    gen c, t, a
-    let field = t[b].immediateVal
-    c.add Arrow
-    c.add "F" & $field
-  of Load:
-    let (_, arg) = sons2(t, n)
-    c.add ParLe
-    c.add "*"
-    gen c, t, arg
-    c.add ParRi
-  of Store:
-    raiseAssert "Assumption was that Store is unused!"
-  of Asgn:
-    let (_, dest, src) = sons3(t, n)
-    gen c, t, dest
-    c.add AsgnOpr
-    gen c, t, src
-    c.add Semicolon
-  of CheckedRange:
-    c.add "nimCheckRange"
-    c.add ParLe
-    let (_, gotoInstr, x, a, b) = sons5(t, n)
-    gen c, t, x
-    c.add Comma
-    gen c, t, a
-    c.add Comma
-    gen c, t, b
-    c.add Comma
-    c.add "L" & $t[gotoInstr].label.int
-    c.add ParRi
-  of CheckedIndex:
-    c.add "nimCheckIndex"
-    c.add ParLe
-    let (gotoInstr, x, a) = sons3(t, n)
-    gen c, t, x
-    c.add Comma
-    gen c, t, a
-    c.add Comma
-    c.add "L" & $t[gotoInstr].label.int
-    c.add ParRi
-  of Call, IndirectCall:
-    let (typ, fn) = sons2(t, n)
-    gen c, t, fn
-    c.add ParLe
-    var i = 0
-    for ch in sonsFromN(t, n, 2):
-      if i > 0: c.add Comma
-      gen c, t, ch
-      inc i
-    c.add ParRi
-    if c.m.types[t[typ].typeId].kind == VoidTy:
-      c.add Semicolon
-  of CheckedCall, CheckedIndirectCall:
-    let (typ, gotoInstr, fn) = sons3(t, n)
-    gen c, t, fn
-    c.add ParLe
-    var i = 0
-    for ch in sonsFromN(t, n, 3):
-      if i > 0: c.add Comma
-      gen c, t, ch
-      inc i
-    c.add ParRi
-    if c.m.types[t[typ].typeId].kind == VoidTy:
-      c.add Semicolon
-
-  of CheckedAdd: checkedBinaryop "nimAddInt"
-  of CheckedSub: checkedBinaryop "nimSubInt"
-  of CheckedMul: checkedBinaryop "nimMulInt"
-  of CheckedDiv: checkedBinaryop "nimDivInt"
-  of CheckedMod: checkedBinaryop "nimModInt"
-  of Add: triop " + "
-  of Sub: triop " - "
-  of Mul: triop " * "
-  of Div: triop " / "
-  of Mod: triop " % "
-  of BitShl: triop " << "
-  of BitShr: triop " >> "
-  of BitAnd: triop " & "
-  of BitOr: triop " | "
-  of BitXor: triop " ^ "
-  of BitNot: binaryop " ~ "
-  of BoolNot: binaryop " !"
-  of Eq: cmpop " == "
-  of Le: cmpop " <= "
-  of Lt: cmpop " < "
-  of Cast: binaryop ""
-  of NumberConv: genNumberConv c, t, n
-  of CheckedObjConv: binaryop ""
-  of ObjConv: binaryop ""
-  of Emit: raiseAssert "cannot interpret: Emit"
-  of ProcDecl: genProcDecl c, t, n, false
-  of ForeignProcDecl: genProcDecl c, t, n, true
-  of PragmaPair, PragmaId, TestOf, Yld, SetExc, TestExc:
-    c.add "cannot interpret: " & $t[n].kind
-
-const
-  Prelude = """
-/* GENERATED CODE. DO NOT EDIT. */
-
-#ifdef __cplusplus
-#define NB8 bool
-#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901)
-// see #13798: to avoid conflicts for code emitting `#include <stdbool.h>`
-#define NB8 _Bool
-#else
-typedef unsigned char NB8; // best effort
-#endif
-
-typedef unsigned char NC8;
-
-typedef float NF32;
-typedef double NF64;
-#if defined(__BORLANDC__) || defined(_MSC_VER)
-typedef signed char NI8;
-typedef signed short int NI16;
-typedef signed int NI32;
-typedef __int64 NI64;
-/* XXX: Float128? */
-typedef unsigned char NU8;
-typedef unsigned short int NU16;
-typedef unsigned int NU32;
-typedef unsigned __int64 NU64;
-#elif defined(HAVE_STDINT_H)
-#ifndef USE_NIM_NAMESPACE
-#  include <stdint.h>
-#endif
-typedef int8_t NI8;
-typedef int16_t NI16;
-typedef int32_t NI32;
-typedef int64_t NI64;
-typedef uint8_t NU8;
-typedef uint16_t NU16;
-typedef uint32_t NU32;
-typedef uint64_t NU64;
-#elif defined(HAVE_CSTDINT)
-#ifndef USE_NIM_NAMESPACE
-#  include <cstdint>
-#endif
-typedef std::int8_t NI8;
-typedef std::int16_t NI16;
-typedef std::int32_t NI32;
-typedef std::int64_t NI64;
-typedef std::uint8_t NU8;
-typedef std::uint16_t NU16;
-typedef std::uint32_t NU32;
-typedef std::uint64_t NU64;
-#else
-/* Unknown compiler/version, do our best */
-#ifdef __INT8_TYPE__
-typedef __INT8_TYPE__ NI8;
-#else
-typedef signed char NI8;
-#endif
-#ifdef __INT16_TYPE__
-typedef __INT16_TYPE__ NI16;
-#else
-typedef signed short int NI16;
-#endif
-#ifdef __INT32_TYPE__
-typedef __INT32_TYPE__ NI32;
-#else
-typedef signed int NI32;
-#endif
-#ifdef __INT64_TYPE__
-typedef __INT64_TYPE__ NI64;
-#else
-typedef long long int NI64;
-#endif
-/* XXX: Float128? */
-#ifdef __UINT8_TYPE__
-typedef __UINT8_TYPE__ NU8;
-#else
-typedef unsigned char NU8;
-#endif
-#ifdef __UINT16_TYPE__
-typedef __UINT16_TYPE__ NU16;
-#else
-typedef unsigned short int NU16;
-#endif
-#ifdef __UINT32_TYPE__
-typedef __UINT32_TYPE__ NU32;
-#else
-typedef unsigned int NU32;
-#endif
-#ifdef __UINT64_TYPE__
-typedef __UINT64_TYPE__ NU64;
-#else
-typedef unsigned long long int NU64;
-#endif
-#endif
-
-#ifdef NIM_INTBITS
-#  if NIM_INTBITS == 64
-typedef NI64 NI;
-typedef NU64 NU;
-#  elif NIM_INTBITS == 32
-typedef NI32 NI;
-typedef NU32 NU;
-#  elif NIM_INTBITS == 16
-typedef NI16 NI;
-typedef NU16 NU;
-#  elif NIM_INTBITS == 8
-typedef NI8 NI;
-typedef NU8 NU;
-#  else
-#    error "invalid bit width for int"
-#  endif
-#endif
-
-#define NIM_STRLIT_FLAG ((NU)(1) << ((NIM_INTBITS) - 2)) /* This has to be the same as system.strlitFlag! */
-
-#define nimAddInt64(a, b, L) ({long long int res; if(__builtin_saddll_overflow(a, b, &res)) goto L; res})
-#define nimSubInt64(a, b, L) ({long long int res; if(__builtin_ssubll_overflow(a, b, &res)) goto L; res})
-#define nimMulInt64(a, b, L) ({long long int res; if(__builtin_smulll_overflow(a, b, &res)) goto L; res})
-
-#define nimAddInt32(a, b, L) ({long int res; if(__builtin_sadd_overflow(a, b, &res)) goto L; res})
-#define nimSubInt32(a, b, L) ({long int res; if(__builtin_ssub_overflow(a, b, &res)) goto L; res})
-#define nimMulInt32(a, b, L) ({long int res; if(__builtin_smul_overflow(a, b, &res)) goto L; res})
-
-#define nimCheckRange(x, a, b, L) ({if (x < a || x > b) goto L; x})
-#define nimCheckIndex(x, a, L) ({if (x >= a) goto L; x})
-
-"""
-
-proc traverseCode(c: var GeneratedCode) =
-  const AllowedInToplevelC = {SummonConst, SummonGlobal, SummonThreadLocal,
-                              ProcDecl, ForeignDecl, ForeignProcDecl}
-  var i = NodePos(0)
-  while i.int < c.m.code.len:
-    let oldLen = c.code.len
-    let moveToInitSection = c.m.code[NodePos(i)].kind notin AllowedInToplevelC
-
-    gen c, c.m.code, NodePos(i)
-    next c.m.code, i
-
-    if moveToInitSection:
-      for i in oldLen ..< c.code.len:
-        c.init.add c.code[i]
-      setLen c.code, oldLen
-
-proc generateCode*(inp, outp: string) =
-  var c = initGeneratedCode(load(inp))
-
-  var co = TypeOrder()
-  traverseTypes(c.m.types, c.m.lit, co)
-
-  generateTypes(c, c.m.types, c.m.lit, co)
-  let typeDecls = move c.code
-
-  traverseCode c
-  var f = CppFile(f: open(outp, fmWrite))
-  f.write "#define NIM_INTBITS " & $c.m.intbits & "\n"
-  f.write Prelude
-  writeTokenSeq f, c.includes, c
-  writeTokenSeq f, typeDecls, c
-  writeTokenSeq f, c.data, c
-  writeTokenSeq f, c.protos, c
-  writeTokenSeq f, c.code, c
-  if c.init.len > 0:
-    f.write "void __attribute__((constructor)) init(void) {"
-    writeTokenSeq f, c.init, c
-    f.write "}\n\n"
-  f.f.close
diff --git a/compiler/nir/nir.nim b/compiler/nir/nir.nim
deleted file mode 100644
index 6f7077fb0..000000000
--- a/compiler/nir/nir.nim
+++ /dev/null
@@ -1,105 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Nim Intermediate Representation, designed to capture all of Nim's semantics without losing too much
-## precious information. Can easily be translated into C. And to JavaScript, hopefully.
-
-from std/os import addFileExt, `/`, createDir
-
-import std / assertions
-import ".." / [ast, modulegraphs, renderer, transf, options, msgs, lineinfos]
-import nirtypes, nirinsts, ast2ir, nirlineinfos, nirfiles, nirvm
-
-import ".." / ic / [rodfiles, bitabs]
-
-type
-  PCtx* = ref object of TPassContext
-    m: ModuleCon
-    c: ProcCon
-    oldErrorCount: int
-    bytecode: Bytecode
-
-proc newCtx*(module: PSym; g: ModuleGraph; idgen: IdGenerator): PCtx =
-  var lit = Literals()
-  var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit)
-  var m = initModuleCon(g, g.config, idgen, module, nirm)
-  m.noModularity = true
-  PCtx(m: m, c: initProcCon(m, nil, g.config), idgen: idgen, bytecode: initBytecode(nirm))
-
-proc refresh*(c: PCtx; module: PSym; idgen: IdGenerator) =
-  #c.m = initModuleCon(c.m.graph, c.m.graph.config, idgen, module, c.m.nirm)
-  #c.m.noModularity = true
-  c.c = initProcCon(c.m, nil, c.m.graph.config)
-  c.idgen = idgen
-
-proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) =
-  if graph.repl.isNil:
-    graph.repl = newCtx(module, graph, idgen)
-    #registerAdditionalOps(PCtx graph.repl)
-  else:
-    refresh(PCtx graph.repl, module, idgen)
-
-proc setupNirReplGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
-  setupGlobalCtx(module, graph, idgen)
-  result = PCtx graph.repl
-
-proc evalStmt(c: PCtx; n: PNode) =
-  let n = transformExpr(c.m.graph, c.idgen, c.m.module, n)
-  let pc = genStmt(c.c, n)
-  #var res = ""
-  #toString c.m.nirm.code, NodePos(pc), c.m.nirm.lit.strings, c.m.nirm.lit.numbers, c.m.symnames, res
-  #res.add "\n--------------------------\n"
-  #toString res, c.m.types.g
-  if pc.int < c.m.nirm.code.len:
-    c.bytecode.interactive = c.m.graph.interactive
-    execCode c.bytecode, c.m.nirm.code, pc
-  #echo res
-
-proc runCode*(c: PPassContext; n: PNode): PNode =
-  let c = PCtx(c)
-  # don't eval errornous code:
-  if c.oldErrorCount == c.m.graph.config.errorCounter:
-    evalStmt(c, n)
-    result = newNodeI(nkEmpty, n.info)
-  else:
-    result = n
-  c.oldErrorCount = c.m.graph.config.errorCounter
-
-type
-  NirPassContext* = ref object of TPassContext
-    m: ModuleCon
-    c: ProcCon
-
-proc openNirBackend*(g: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
-  var lit = Literals()
-  var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit)
-  let m = initModuleCon(g, g.config, idgen, module, nirm)
-  NirPassContext(m: m, c: initProcCon(m, nil, g.config), idgen: idgen)
-
-proc gen(c: NirPassContext; n: PNode) =
-  let n = transformExpr(c.m.graph, c.idgen, c.m.module, n)
-  let pc = genStmt(c.c, n)
-
-proc nirBackend*(c: PPassContext; n: PNode): PNode =
-  gen(NirPassContext(c), n)
-  result = n
-
-proc closeNirBackend*(c: PPassContext; finalNode: PNode) =
-  discard nirBackend(c, finalNode)
-
-  let c = NirPassContext(c)
-  let nimcache = getNimcacheDir(c.c.config).string
-  createDir nimcache
-  let outp = nimcache / c.m.module.name.s.addFileExt("nir")
-  #c.m.nirm.code = move c.c.code
-  try:
-    store c.m.nirm[], outp
-    echo "created: ", outp
-  except IOError:
-    rawMessage(c.c.config, errFatal, "serialization failed: " & outp)
diff --git a/compiler/nir/nirc.nim b/compiler/nir/nirc.nim
deleted file mode 100644
index a2cf69988..000000000
--- a/compiler/nir/nirc.nim
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Nir Compiler.
-
-import ".." / ic / [bitabs, rodfiles]
-import nirinsts, nirtypes, nirlineinfos, nirfiles, cir
-
-proc view(filename: string) =
-  let m = load(filename)
-  var res = ""
-  allTreesToString m.code, m.lit.strings, m.lit.numbers, m.symnames, res
-  res.add "\n# TYPES\n"
-  nirtypes.toString res, m.types
-  echo res
-
-import std / [syncio, parseopt]
-
-proc writeHelp =
-  echo """Usage: nirc view|c <file.nir>"""
-  quit 0
-
-proc main =
-  var inp = ""
-  var cmd = ""
-  for kind, key, val in getopt():
-    case kind
-    of cmdArgument:
-      if cmd.len == 0: cmd = key
-      elif inp.len == 0: inp = key
-      else: quit "Error: too many arguments"
-    of cmdLongOption, cmdShortOption:
-      case key
-      of "help", "h": writeHelp()
-      of "version", "v": stdout.write "1.0\n"
-    of cmdEnd: discard
-  if inp.len == 0:
-    quit "Error: no input file specified"
-  case cmd
-  of "", "view":
-    view inp
-  of "c":
-    let outp = inp & ".c"
-    cir.generateCode inp, outp
-
-main()
diff --git a/compiler/nir/nirfiles.nim b/compiler/nir/nirfiles.nim
deleted file mode 100644
index cd5a79f06..000000000
--- a/compiler/nir/nirfiles.nim
+++ /dev/null
@@ -1,83 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-import ".." / ic / [bitabs, rodfiles]
-import nirinsts, nirtypes, nirlineinfos
-
-type
-  NirModule* = object
-    code*: Tree
-    man*: LineInfoManager
-    types*: TypeGraph
-    lit*: Literals
-    namespace*: LitId
-    intbits*: uint32
-    symnames*: SymNames
-
-proc load*(filename: string): NirModule =
-  let lit = Literals()
-  result = NirModule(lit: lit, types: initTypeGraph(lit))
-  var r = rodfiles.open(filename)
-  try:
-    r.loadHeader(nirCookie)
-    r.loadSection stringsSection
-    r.load result.lit.strings
-
-    r.loadSection numbersSection
-    r.load result.lit.numbers
-
-    r.loadSection bodiesSection
-    r.load result.code
-
-    r.loadSection typesSection
-    r.load result.types
-
-    r.loadSection sideChannelSection
-    r.load result.man
-
-    r.loadSection namespaceSection
-    r.loadPrim result.namespace
-    r.loadPrim result.intbits
-
-    r.loadSection symnamesSection
-    r.load result.symnames
-
-  finally:
-    r.close()
-
-proc store*(m: NirModule; outp: string) =
-  var r = rodfiles.create(outp)
-  try:
-    r.storeHeader(nirCookie)
-    r.storeSection stringsSection
-    r.store m.lit.strings
-
-    r.storeSection numbersSection
-    r.store m.lit.numbers
-
-    r.storeSection bodiesSection
-    r.store m.code
-
-    r.storeSection typesSection
-    r.store m.types
-
-    r.storeSection sideChannelSection
-    r.store m.man
-
-    r.storeSection namespaceSection
-    r.storePrim m.namespace
-    r.storePrim m.intbits
-
-    r.storeSection symnamesSection
-    r.store m.symnames
-
-  finally:
-    r.close()
-  if r.err != ok:
-    raise newException(IOError, "could store into: " & outp)
diff --git a/compiler/nir/nirinsts.nim b/compiler/nir/nirinsts.nim
deleted file mode 100644
index 6cffc1a89..000000000
--- a/compiler/nir/nirinsts.nim
+++ /dev/null
@@ -1,582 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## NIR instructions. Somewhat inspired by LLVM's instructions.
-
-import std / [assertions, hashes]
-import .. / ic / [bitabs, rodfiles]
-import nirlineinfos, nirtypes
-
-const
-  NirVersion = 1
-  nirCookie* = [byte(0), byte('N'), byte('I'), byte('R'),
-            byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(NirVersion)]
-
-type
-  SymId* = distinct int
-
-proc `$`*(s: SymId): string {.borrow.}
-proc hash*(s: SymId): Hash {.borrow.}
-proc `==`*(a, b: SymId): bool {.borrow.}
-
-type
-  Opcode* = enum
-    Nop,
-    ImmediateVal,
-    IntVal,
-    StrVal,
-    SymDef,
-    SymUse,
-    Typed,   # with type ID
-    PragmaId, # with Pragma ID, possible values: see PragmaKey enum
-    NilVal,
-    Label,
-    Goto,
-    CheckedGoto,
-    LoopLabel,
-    GotoLoop,  # last atom
-
-    ModuleSymUse, # `"module".x`
-
-    ArrayConstr,
-    ObjConstr,
-    Ret,
-    Yld,
-
-    Select,
-    SelectPair,  # ((values...), Label)
-    SelectList,  # (values...)
-    SelectValue, # (value)
-    SelectRange, # (valueA..valueB)
-    ForeignDecl, # Can wrap SummonGlobal, SummonThreadLocal, SummonConst
-    SummonGlobal,
-    SummonThreadLocal,
-    Summon, # x = Summon Typed <Type ID>; x begins to live
-    SummonResult,
-    SummonParam,
-    SummonConst,
-    Kill, # `Kill x`: scope end for `x`
-
-    AddrOf,
-    ArrayAt, # a[i]
-    DerefArrayAt, # a[i] where `a` is a PtrArray; `a[][i]`
-    FieldAt, # obj.field
-    DerefFieldAt, # obj[].field
-
-    Load, # a[]
-    Store, # a[] = b
-    Asgn,  # a = b
-    SetExc,
-    TestExc,
-
-    CheckedRange,
-    CheckedIndex,
-
-    Call,
-    IndirectCall,
-    CheckedCall, # call that can raise
-    CheckedIndirectCall, # call that can raise
-    CheckedAdd, # with overflow checking etc.
-    CheckedSub,
-    CheckedMul,
-    CheckedDiv,
-    CheckedMod,
-    Add,
-    Sub,
-    Mul,
-    Div,
-    Mod,
-    BitShl,
-    BitShr,
-    BitAnd,
-    BitOr,
-    BitXor,
-    BitNot,
-    BoolNot,
-    Eq,
-    Le,
-    Lt,
-    Cast,
-    NumberConv,
-    CheckedObjConv,
-    ObjConv,
-    TestOf,
-    Emit,
-    ProcDecl,
-    ForeignProcDecl,
-    PragmaPair
-
-type
-  PragmaKey* = enum
-    FastCall, StdCall, CDeclCall, SafeCall, SysCall, InlineCall, NoinlineCall, ThisCall, NoCall,
-    CoreName,
-    ExternName,
-    HeaderImport,
-    DllImport,
-    DllExport,
-    ObjExport
-
-const
-  LastAtomicValue = GotoLoop
-
-  OpcodeBits = 8'u32
-  OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
-
-  ValueProducingAtoms = {ImmediateVal, IntVal, StrVal, SymUse, NilVal}
-
-  ValueProducing* = {
-    ImmediateVal,
-    IntVal,
-    StrVal,
-    SymUse,
-    NilVal,
-    ModuleSymUse,
-    ArrayConstr,
-    ObjConstr,
-    CheckedAdd,
-    CheckedSub,
-    CheckedMul,
-    CheckedDiv,
-    CheckedMod,
-    Add,
-    Sub,
-    Mul,
-    Div,
-    Mod,
-    BitShl,
-    BitShr,
-    BitAnd,
-    BitOr,
-    BitXor,
-    BitNot,
-    BoolNot,
-    Eq,
-    Le,
-    Lt,
-    Cast,
-    NumberConv,
-    CheckedObjConv,
-    ObjConv,
-    AddrOf,
-    Load,
-    ArrayAt,
-    DerefArrayAt,
-    FieldAt,
-    DerefFieldAt,
-    TestOf
-  }
-
-type
-  Instr* = object     # 8 bytes
-    x: uint32
-    info*: PackedLineInfo
-
-template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask)
-template operand(n: Instr): uint32 = (n.x shr OpcodeBits)
-
-template rawOperand*(n: Instr): uint32 = (n.x shr OpcodeBits)
-
-template toX(k: Opcode; operand: uint32): uint32 =
-  uint32(k) or (operand shl OpcodeBits)
-
-template toX(k: Opcode; operand: LitId): uint32 =
-  uint32(k) or (operand.uint32 shl OpcodeBits)
-
-type
-  Tree* = object
-    nodes: seq[Instr]
-
-  Values* = object
-    numbers: BiTable[int64]
-    strings: BiTable[string]
-
-type
-  PatchPos* = distinct int
-  NodePos* = distinct int
-
-const
-  InvalidPatchPos* = PatchPos(-1)
-
-proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
-
-proc prepare*(tree: var Tree; info: PackedLineInfo; kind: Opcode): PatchPos =
-  result = PatchPos tree.nodes.len
-  tree.nodes.add Instr(x: toX(kind, 1'u32), info: info)
-
-proc isAtom(tree: Tree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
-proc isAtom(tree: Tree; pos: NodePos): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
-
-proc patch*(tree: var Tree; pos: PatchPos) =
-  let pos = pos.int
-  let k = tree.nodes[pos].kind
-  assert k > LastAtomicValue
-  let distance = int32(tree.nodes.len - pos)
-  assert distance > 0
-  tree.nodes[pos].x = toX(k, cast[uint32](distance))
-
-template build*(tree: var Tree; info: PackedLineInfo; kind: Opcode; body: untyped) =
-  let pos = prepare(tree, info, kind)
-  body
-  patch(tree, pos)
-
-template buildTyped*(tree: var Tree; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) =
-  let pos = prepare(tree, info, kind)
-  tree.addTyped info, typ
-  body
-  patch(tree, pos)
-
-proc len*(tree: Tree): int {.inline.} = tree.nodes.len
-
-template rawSpan(n: Instr): int = int(operand(n))
-
-proc nextChild(tree: Tree; pos: var int) {.inline.} =
-  if tree.nodes[pos].kind > LastAtomicValue:
-    assert tree.nodes[pos].operand > 0'u32
-    inc pos, tree.nodes[pos].rawSpan
-  else:
-    inc pos
-
-proc next*(tree: Tree; pos: var NodePos) {.inline.} = nextChild tree, int(pos)
-
-template firstSon*(n: NodePos): NodePos = NodePos(n.int+1)
-
-template skipTyped*(n: NodePos): NodePos = NodePos(n.int+2)
-
-iterator sons*(tree: Tree; n: NodePos): NodePos =
-  var pos = n.int
-  assert tree.nodes[pos].kind > LastAtomicValue
-  let last = pos + tree.nodes[pos].rawSpan
-  inc pos
-  while pos < last:
-    yield NodePos pos
-    nextChild tree, pos
-
-iterator sonsFrom1*(tree: Tree; n: NodePos): NodePos =
-  var pos = n.int
-  assert tree.nodes[pos].kind > LastAtomicValue
-  let last = pos + tree.nodes[pos].rawSpan
-  inc pos
-  nextChild tree, pos
-  while pos < last:
-    yield NodePos pos
-    nextChild tree, pos
-
-iterator sonsFromN*(tree: Tree; n: NodePos; toSkip = 2): NodePos =
-  var pos = n.int
-  assert tree.nodes[pos].kind > LastAtomicValue
-  let last = pos + tree.nodes[pos].rawSpan
-  inc pos
-  for i in 1..toSkip:
-    nextChild tree, pos
-  while pos < last:
-    yield NodePos pos
-    nextChild tree, pos
-
-template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int]
-
-iterator sonsRest*(tree: Tree; parent, n: NodePos): NodePos =
-  var pos = n.int
-  assert tree[parent].kind > LastAtomicValue
-  let last = parent.int + tree[parent].rawSpan
-  while pos < last:
-    yield NodePos pos
-    nextChild tree, pos
-
-proc span(tree: Tree; pos: int): int {.inline.} =
-  if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
-
-proc copyTree*(dest: var Tree; src: Tree) =
-  let pos = 0
-  let L = span(src, pos)
-  let d = dest.nodes.len
-  dest.nodes.setLen(d + L)
-  assert L > 0
-  for i in 0..<L:
-    dest.nodes[d+i] = src.nodes[pos+i]
-
-proc sons2*(tree: Tree; n: NodePos): (NodePos, NodePos) {.inline.} =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  result = (NodePos a, NodePos b)
-
-proc sons3*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos) {.inline.} =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  result = (NodePos a, NodePos b, NodePos c)
-
-proc sons4*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos) {.inline.} =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  let d = c + span(tree, c)
-  result = (NodePos a, NodePos b, NodePos c, NodePos d)
-
-proc sons5*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos, NodePos) {.inline.} =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  let d = c + span(tree, c)
-  let e = d + span(tree, d)
-  result = (NodePos a, NodePos b, NodePos c, NodePos d, NodePos e)
-
-proc typeId*(ins: Instr): TypeId {.inline.} =
-  assert ins.kind == Typed
-  result = TypeId(ins.operand)
-
-proc symId*(ins: Instr): SymId {.inline.} =
-  assert ins.kind in {SymUse, SymDef}
-  result = SymId(ins.operand)
-
-proc immediateVal*(ins: Instr): int {.inline.} =
-  assert ins.kind == ImmediateVal
-  result = cast[int](ins.operand)
-
-proc litId*(ins: Instr): LitId {.inline.} =
-  assert ins.kind in {StrVal, IntVal}
-  result = LitId(ins.operand)
-
-
-type
-  LabelId* = distinct int
-
-proc `==`*(a, b: LabelId): bool {.borrow.}
-proc hash*(a: LabelId): Hash {.borrow.}
-
-proc label*(ins: Instr): LabelId {.inline.} =
-  assert ins.kind in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
-  result = LabelId(ins.operand)
-
-proc newLabel*(labelGen: var int): LabelId {.inline.} =
-  result = LabelId labelGen
-  inc labelGen
-
-proc newLabels*(labelGen: var int; n: int): LabelId {.inline.} =
-  result = LabelId labelGen
-  inc labelGen, n
-
-proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcode): LabelId =
-  assert k in {Label, LoopLabel}
-  result = LabelId labelGen
-  t.nodes.add Instr(x: toX(k, uint32(result)), info: info)
-  inc labelGen
-
-proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) =
-  assert k in {Goto, GotoLoop, CheckedGoto}
-  t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
-
-proc addLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) {.inline.} =
-  assert k in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
-  t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
-
-proc addSymUse*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
-  t.nodes.add Instr(x: toX(SymUse, uint32(s)), info: info)
-
-proc addSymDef*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
-  t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
-
-proc addNop*(t: var Tree; info: PackedLineInfo) {.inline.} =
-  t.nodes.add Instr(x: toX(Nop, 0'u32), info: info)
-
-proc addTyped*(t: var Tree; info: PackedLineInfo; typ: TypeId) {.inline.} =
-  assert typ.int >= 0
-  t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
-
-proc addSummon*(t: var Tree; info: PackedLineInfo; s: SymId; typ: TypeId; opc = Summon) {.inline.} =
-  assert typ.int >= 0
-  assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam, SummonResult}
-  let x = prepare(t, info, opc)
-  t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
-  t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
-  patch t, x
-
-proc addImmediateVal*(t: var Tree; info: PackedLineInfo; x: int) =
-  assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
-  t.nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
-
-proc addPragmaId*(t: var Tree; info: PackedLineInfo; x: PragmaKey) =
-  t.nodes.add Instr(x: toX(PragmaId, uint32(x)), info: info)
-
-proc addIntVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) =
-  buildTyped t, info, NumberConv, typ:
-    t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(x))), info: info)
-
-proc boolVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; b: bool) =
-  buildTyped t, info, NumberConv, Bool8Id:
-    t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(ord b))), info: info)
-
-proc addStrVal*(t: var Tree; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
-  t.nodes.add Instr(x: toX(StrVal, uint32(strings.getOrIncl(s))), info: info)
-
-proc addStrLit*(t: var Tree; info: PackedLineInfo; s: LitId) =
-  t.nodes.add Instr(x: toX(StrVal, uint32(s)), info: info)
-
-proc addNilVal*(t: var Tree; info: PackedLineInfo; typ: TypeId) =
-  buildTyped t, info, NumberConv, typ:
-    t.nodes.add Instr(x: toX(NilVal, uint32(0)), info: info)
-
-proc store*(r: var RodFile; t: Tree) = storeSeq r, t.nodes
-proc load*(r: var RodFile; t: var Tree) = loadSeq r, t.nodes
-
-proc escapeToNimLit*(s: string; result: var string) =
-  result.add '"'
-  for c in items s:
-    if c < ' ' or int(c) >= 128:
-      result.add '\\'
-      result.addInt int(c)
-    elif c == '\\':
-      result.add r"\\"
-    elif c == '\n':
-      result.add r"\n"
-    elif c == '\r':
-      result.add r"\r"
-    elif c == '\t':
-      result.add r"\t"
-    else:
-      result.add c
-  result.add '"'
-
-type
-  SymNames* = object
-    s: seq[LitId]
-
-proc `[]=`*(t: var SymNames; key: SymId; val: LitId) =
-  let k = int(key)
-  if k >= t.s.len: t.s.setLen k+1
-  t.s[k] = val
-
-proc `[]`*(t: SymNames; key: SymId): LitId =
-  let k = int(key)
-  if k < t.s.len: result = t.s[k]
-  else: result = LitId(0)
-
-template localName(s: SymId): string =
-  let name = names[s]
-  if name != LitId(0):
-    strings[name]
-  else:
-    $s.int
-
-proc store*(r: var RodFile; t: SymNames) = storeSeq(r, t.s)
-proc load*(r: var RodFile; t: var SymNames) = loadSeq(r, t.s)
-
-proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTable[int64];
-               names: SymNames;
-               r: var string; nesting = 0) =
-  if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}:
-    r.add ' '
-
-  case t[pos].kind
-  of Nop: r.add "Nop"
-  of ImmediateVal:
-    r.add $t[pos].operand
-  of IntVal:
-    r.add "IntVal "
-    r.add $integers[LitId t[pos].operand]
-  of StrVal:
-    escapeToNimLit(strings[LitId t[pos].operand], r)
-  of SymDef:
-    r.add "SymDef "
-    r.add localName(SymId t[pos].operand)
-  of SymUse:
-    r.add "SymUse "
-    r.add localName(SymId t[pos].operand)
-  of PragmaId:
-    r.add $cast[PragmaKey](t[pos].operand)
-  of Typed:
-    r.add "T<"
-    r.add $t[pos].operand
-    r.add ">"
-  of NilVal:
-    r.add "NilVal"
-  of Label:
-    # undo the nesting:
-    var spaces = r.len-1
-    while spaces >= 0 and r[spaces] == ' ': dec spaces
-    r.setLen spaces+1
-    r.add "\n  L"
-    r.add $t[pos].operand
-  of Goto, CheckedGoto, LoopLabel, GotoLoop:
-    r.add $t[pos].kind
-    r.add " L"
-    r.add $t[pos].operand
-  else:
-    r.add $t[pos].kind
-    r.add "{\n"
-    for i in 0..<(nesting+1)*2: r.add ' '
-    for p in sons(t, pos):
-      toString t, p, strings, integers, names, r, nesting+1
-    r.add "\n"
-    for i in 0..<nesting*2: r.add ' '
-    r.add "}"
-
-proc allTreesToString*(t: Tree; strings: BiTable[string]; integers: BiTable[int64];
-                       names: SymNames;
-                       r: var string) =
-  var i = 0
-  while i < t.len:
-    toString t, NodePos(i), strings, integers, names, r
-    nextChild t, i
-
-type
-  Value* = distinct Tree
-
-proc prepare*(dest: var Value; info: PackedLineInfo; k: Opcode): PatchPos {.inline.} =
-  assert k in ValueProducing - ValueProducingAtoms
-  result = prepare(Tree(dest), info, k)
-
-proc patch*(dest: var Value; pos: PatchPos) {.inline.} =
-  patch(Tree(dest), pos)
-
-proc localToValue*(info: PackedLineInfo; s: SymId): Value =
-  result = Value(Tree())
-  Tree(result).addSymUse info, s
-
-proc hasValue*(v: Value): bool {.inline.} = Tree(v).len > 0
-
-proc isEmpty*(v: Value): bool {.inline.} = Tree(v).len == 0
-
-proc extractTemp*(v: Value): SymId =
-  if hasValue(v) and Tree(v)[NodePos 0].kind == SymUse:
-    result = SymId(Tree(v)[NodePos 0].operand)
-  else:
-    result = SymId(-1)
-
-proc copyTree*(dest: var Tree; src: Value) = copyTree dest, Tree(src)
-
-proc addImmediateVal*(t: var Value; info: PackedLineInfo; x: int) =
-  assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
-  Tree(t).nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
-
-template build*(tree: var Value; info: PackedLineInfo; kind: Opcode; body: untyped) =
-  let pos = prepare(Tree(tree), info, kind)
-  body
-  patch(tree, pos)
-
-proc addTyped*(t: var Value; info: PackedLineInfo; typ: TypeId) {.inline.} =
-  addTyped(Tree(t), info, typ)
-
-template buildTyped*(tree: var Value; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) =
-  let pos = prepare(tree, info, kind)
-  tree.addTyped info, typ
-  body
-  patch(tree, pos)
-
-proc addStrVal*(t: var Value; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
-  addStrVal(Tree(t), strings, info, s)
-
-proc addNilVal*(t: var Value; info: PackedLineInfo; typ: TypeId) =
-  addNilVal Tree(t), info, typ
-
-proc addIntVal*(t: var Value; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) =
-  addIntVal Tree(t), integers, info, typ, x
diff --git a/compiler/nir/nirslots.nim b/compiler/nir/nirslots.nim
deleted file mode 100644
index a01e7a633..000000000
--- a/compiler/nir/nirslots.nim
+++ /dev/null
@@ -1,104 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Management of slots. Similar to "register allocation"
-## in lower level languages.
-
-import std / [assertions, tables]
-import nirtypes, nirinsts
-
-type
-  SlotManagerFlag* = enum
-    ReuseTemps,
-    ReuseVars
-  SlotKind* = enum
-    Temp, Perm
-  SlotManager* = object # "register allocator"
-    live: Table[SymId, (SlotKind, TypeId)]
-    dead: Table[TypeId, seq[SymId]]
-    flags: set[SlotManagerFlag]
-    inScope: seq[SymId]
-
-proc initSlotManager*(flags: set[SlotManagerFlag]): SlotManager {.inline.} =
-  SlotManager(flags: flags)
-
-proc allocRaw(m: var SlotManager; t: TypeId; f: SlotManagerFlag; k: SlotKind;
-              symIdgen: var int32): SymId {.inline.} =
-  if f in m.flags and m.dead.hasKey(t) and m.dead[t].len > 0:
-    result = m.dead[t].pop()
-  else:
-    inc symIdgen
-    result = SymId(symIdgen)
-    m.inScope.add result
-  m.live[result] = (k, t)
-
-proc allocTemp*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} =
-  result = allocRaw(m, t, ReuseTemps, Temp, symIdgen)
-
-proc allocVar*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} =
-  result = allocRaw(m, t, ReuseVars, Perm, symIdgen)
-
-proc freeLoc*(m: var SlotManager; s: SymId) =
-  let t = m.live.getOrDefault(s)
-  assert t[1].int != 0
-  m.live.del s
-  m.dead.mgetOrPut(t[1], @[]).add s
-
-proc freeTemp*(m: var SlotManager; s: SymId) =
-  let t = m.live.getOrDefault(s)
-  if t[1].int != 0 and t[0] == Temp:
-    m.live.del s
-    m.dead.mgetOrPut(t[1], @[]).add s
-
-iterator stillAlive*(m: SlotManager): (SymId, TypeId) =
-  for k, v in pairs(m.live):
-    yield (k, v[1])
-
-proc getType*(m: SlotManager; s: SymId): TypeId {.inline.} = m.live[s][1]
-
-proc openScope*(m: var SlotManager) =
-  m.inScope.add SymId(-1) # add marker
-
-proc closeScope*(m: var SlotManager) =
-  var i = m.inScope.len - 1
-  while i >= 0:
-    if m.inScope[i] == SymId(-1):
-      m.inScope.setLen i
-      break
-    dec i
-
-when isMainModule:
-  var symIdgen: int32
-  var m = initSlotManager({ReuseTemps})
-
-  var g = initTypeGraph(Literals())
-
-  let a = g.openType ArrayTy
-  g.addBuiltinType Int8Id
-  g.addArrayLen 5
-  let finalArrayType = finishType(g, a)
-
-  let obj = g.openType ObjectDecl
-  g.addName "MyType"
-
-  g.addField "p", finalArrayType, 0
-  let objB = finishType(g, obj)
-
-  let x = m.allocTemp(objB, symIdgen)
-  assert x.int == 0
-
-  let y = m.allocTemp(objB, symIdgen)
-  assert y.int == 1
-
-  let z = m.allocTemp(Int8Id, symIdgen)
-  assert z.int == 2
-
-  m.freeLoc y
-  let y2 = m.allocTemp(objB, symIdgen)
-  assert y2.int == 1
diff --git a/compiler/nir/nirtypes.nim b/compiler/nir/nirtypes.nim
deleted file mode 100644
index a79bf6d01..000000000
--- a/compiler/nir/nirtypes.nim
+++ /dev/null
@@ -1,475 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Type system for NIR. Close to C's type system but without its quirks.
-
-import std / [assertions, hashes]
-import .. / ic / [bitabs, rodfiles]
-
-type
-  NirTypeKind* = enum
-    VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal,
-    IntVal, SizeVal, AlignVal, OffsetVal,
-    AnnotationVal,
-    ObjectTy,
-    UnionTy,
-    VarargsTy, # the `...` in a C prototype; also the last "atom"
-    APtrTy, # pointer to aliasable memory
-    UPtrTy, # pointer to unique/unaliasable memory
-    AArrayPtrTy, # pointer to array of aliasable memory
-    UArrayPtrTy, # pointer to array of unique/unaliasable memory
-    ArrayTy,
-    LastArrayTy, # array of unspecified size as a last field inside an object
-    ProcTy,
-    ObjectDecl,
-    UnionDecl,
-    FieldDecl
-
-const
-  TypeKindBits = 8'u32
-  TypeKindMask = (1'u32 shl TypeKindBits) - 1'u32
-
-type
-  TypeNode* = object     # 4 bytes
-    x: uint32
-
-template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask)
-template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits)
-
-proc integralBits*(n: TypeNode): int {.inline.} =
-  # Number of bits in the IntTy, etc. Only valid for integral types.
-  assert n.kind in {IntTy, UIntTy, FloatTy, BoolTy, CharTy}
-  result = int(n.operand)
-
-template toX(k: NirTypeKind; operand: uint32): uint32 =
-  uint32(k) or (operand shl TypeKindBits)
-
-template toX(k: NirTypeKind; operand: LitId): uint32 =
-  uint32(k) or (operand.uint32 shl TypeKindBits)
-
-type
-  TypeId* = distinct int
-
-proc `==`*(a, b: TypeId): bool {.borrow.}
-proc hash*(a: TypeId): Hash {.borrow.}
-
-type
-  Literals* = ref object
-    strings*: BiTable[string]
-    numbers*: BiTable[int64]
-
-  TypeGraph* = object
-    nodes: seq[TypeNode]
-    lit: Literals
-
-const
-  VoidId* = TypeId 0
-  Bool8Id* = TypeId 1
-  Char8Id* = TypeId 2
-  Int8Id* = TypeId 3
-  Int16Id* = TypeId 4
-  Int32Id* = TypeId 5
-  Int64Id* = TypeId 6
-  UInt8Id* = TypeId 7
-  UInt16Id* = TypeId 8
-  UInt32Id* = TypeId 9
-  UInt64Id* = TypeId 10
-  Float32Id* = TypeId 11
-  Float64Id* = TypeId 12
-  VoidPtrId* = TypeId 13
-  LastBuiltinId* = 13
-
-proc initTypeGraph*(lit: Literals): TypeGraph =
-  result = TypeGraph(nodes: @[
-    TypeNode(x: toX(VoidTy, 0'u32)),
-    TypeNode(x: toX(BoolTy, 8'u32)),
-    TypeNode(x: toX(CharTy, 8'u32)),
-    TypeNode(x: toX(IntTy, 8'u32)),
-    TypeNode(x: toX(IntTy, 16'u32)),
-    TypeNode(x: toX(IntTy, 32'u32)),
-    TypeNode(x: toX(IntTy, 64'u32)),
-    TypeNode(x: toX(UIntTy, 8'u32)),
-    TypeNode(x: toX(UIntTy, 16'u32)),
-    TypeNode(x: toX(UIntTy, 32'u32)),
-    TypeNode(x: toX(UIntTy, 64'u32)),
-    TypeNode(x: toX(FloatTy, 32'u32)),
-    TypeNode(x: toX(FloatTy, 64'u32)),
-    TypeNode(x: toX(APtrTy, 2'u32)),
-    TypeNode(x: toX(VoidTy, 0'u32))
-  ], lit: lit)
-  assert result.nodes.len == LastBuiltinId+2
-
-type
-  TypePatchPos* = distinct int
-
-const
-  InvalidTypePatchPos* = TypePatchPos(-1)
-  LastAtomicValue = VarargsTy
-
-proc isValid(p: TypePatchPos): bool {.inline.} = p.int != -1
-
-proc prepare(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
-  result = TypePatchPos tree.nodes.len
-  tree.nodes.add TypeNode(x: toX(kind, 1'u32))
-
-proc isAtom(tree: TypeGraph; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
-proc isAtom(tree: TypeGraph; pos: TypeId): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
-
-proc patch(tree: var TypeGraph; pos: TypePatchPos) =
-  let pos = pos.int
-  let k = tree.nodes[pos].kind
-  assert k > LastAtomicValue
-  let distance = int32(tree.nodes.len - pos)
-  assert distance > 0
-  tree.nodes[pos].x = toX(k, cast[uint32](distance))
-
-proc len*(tree: TypeGraph): int {.inline.} = tree.nodes.len
-
-template rawSpan(n: TypeNode): int = int(operand(n))
-
-proc nextChild(tree: TypeGraph; pos: var int) {.inline.} =
-  if tree.nodes[pos].kind > LastAtomicValue:
-    assert tree.nodes[pos].operand > 0'u32
-    inc pos, tree.nodes[pos].rawSpan
-  else:
-    inc pos
-
-iterator sons*(tree: TypeGraph; n: TypeId): TypeId =
-  var pos = n.int
-  assert tree.nodes[pos].kind > LastAtomicValue
-  let last = pos + tree.nodes[pos].rawSpan
-  inc pos
-  while pos < last:
-    yield TypeId pos
-    nextChild tree, pos
-
-template `[]`*(t: TypeGraph; n: TypeId): TypeNode = t.nodes[n.int]
-
-proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
-  assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy}
-  result = TypeId(n.int+1)
-
-proc litId*(n: TypeNode): LitId {.inline.} =
-  assert n.kind in {NameVal, IntVal, SizeVal, AlignVal, OffsetVal, AnnotationVal, ObjectTy, UnionTy}
-  result = LitId(n.operand)
-
-proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind
-
-proc span(tree: TypeGraph; pos: int): int {.inline.} =
-  if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
-
-proc sons2(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  result = (TypeId a, TypeId b)
-
-proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) =
-  assert(not isAtom(tree, n.int))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  result = (TypeId a, TypeId b, TypeId c)
-
-proc arrayName*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
-  assert tree[n].kind == ArrayTy
-  let (_, _, c) = sons3(tree, n)
-  result = c
-
-proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestInt =
-  assert tree[n].kind == ArrayTy
-  let (_, b) = sons2(tree, n)
-  result = tree.lit.numbers[LitId tree[b].operand]
-
-proc returnType*(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
-  # Returns the positions of the return type + calling convention.
-  var pos = n.int
-  assert tree.nodes[pos].kind == ProcTy
-  let a = n.int+1
-  let b = a + span(tree, a)
-  result = (TypeId b, TypeId a) # not a typo, order is reversed
-
-iterator params*(tree: TypeGraph; n: TypeId): TypeId =
-  var pos = n.int
-  assert tree.nodes[pos].kind == ProcTy
-  let last = pos + tree.nodes[pos].rawSpan
-  inc pos
-  nextChild tree, pos
-  nextChild tree, pos
-  while pos < last:
-    yield TypeId pos
-    nextChild tree, pos
-
-proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
-  assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy,
-    ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl,
-    FieldDecl}
-  result = prepare(tree, kind)
-
-template typeInvariant(p: TypePatchPos) =
-  when false:
-    if tree[TypeId(p)].kind == FieldDecl:
-      var k = 0
-      for ch in sons(tree, TypeId(p)):
-        inc k
-      assert k > 2, "damn! " & $k
-
-proc sealType*(tree: var TypeGraph; p: TypePatchPos) =
-  patch tree, p
-  typeInvariant(p)
-
-proc finishType*(tree: var TypeGraph; p: TypePatchPos): TypeId =
-  # Search for an existing instance of this type in
-  # order to reduce memory consumption:
-  patch tree, p
-  typeInvariant(p)
-
-  let s = span(tree, p.int)
-  var i = 0
-  while i < p.int:
-    if tree.nodes[i].x == tree.nodes[p.int].x:
-      var isMatch = true
-      for j in 1..<s:
-        if tree.nodes[j+i].x == tree.nodes[j+p.int].x:
-          discard "still a match"
-        else:
-          isMatch = false
-          break
-      if isMatch:
-        if p.int+s == tree.len:
-          setLen tree.nodes, p.int
-        return TypeId(i)
-    nextChild tree, i
-  result = TypeId(p)
-
-proc nominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string): TypeId =
-  assert kind in {ObjectTy, UnionTy}
-  let content = TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
-  for i in 0..<tree.len:
-    if tree.nodes[i].x == content.x:
-      return TypeId(i)
-  result = TypeId tree.nodes.len
-  tree.nodes.add content
-
-proc addNominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string) =
-  assert kind in {ObjectTy, UnionTy}
-  tree.nodes.add TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
-
-proc getTypeTag*(tree: TypeGraph; t: TypeId): string =
-  assert tree[t].kind in {ObjectTy, UnionTy}
-  result = tree.lit.strings[LitId tree[t].operand]
-
-proc addVarargs*(tree: var TypeGraph) =
-  tree.nodes.add TypeNode(x: toX(VarargsTy, 0'u32))
-
-proc getFloat128Type*(tree: var TypeGraph): TypeId =
-  result = TypeId tree.nodes.len
-  tree.nodes.add TypeNode(x: toX(FloatTy, 128'u32))
-
-proc addBuiltinType*(g: var TypeGraph; id: TypeId) =
-  g.nodes.add g[id]
-
-template firstSon*(n: TypeId): TypeId = TypeId(n.int+1)
-
-proc addType*(g: var TypeGraph; t: TypeId) =
-  # We cannot simply copy `*Decl` nodes. We have to introduce `*Ty` nodes instead:
-  if g[t].kind in {ObjectDecl, UnionDecl}:
-    assert g[t.firstSon].kind == NameVal
-    let name = LitId g[t.firstSon].operand
-    if g[t].kind == ObjectDecl:
-      g.nodes.add TypeNode(x: toX(ObjectTy, name))
-    else:
-      g.nodes.add TypeNode(x: toX(UnionTy, name))
-  else:
-    let pos = t.int
-    let L = span(g, pos)
-    let d = g.nodes.len
-    g.nodes.setLen(d + L)
-    assert L > 0
-    for i in 0..<L:
-      g.nodes[d+i] = g.nodes[pos+i]
-
-proc addArrayLen*(g: var TypeGraph; len: int64) =
-  g.nodes.add TypeNode(x: toX(IntVal, g.lit.numbers.getOrIncl(len)))
-
-proc addSize*(g: var TypeGraph; s: int64) =
-  g.nodes.add TypeNode(x: toX(SizeVal, g.lit.numbers.getOrIncl(s)))
-
-proc addOffset*(g: var TypeGraph; offset: int64) =
-  g.nodes.add TypeNode(x: toX(OffsetVal, g.lit.numbers.getOrIncl(offset)))
-
-proc addAlign*(g: var TypeGraph; a: int64) =
-  g.nodes.add TypeNode(x: toX(AlignVal, g.lit.numbers.getOrIncl(a)))
-
-proc addName*(g: var TypeGraph; name: string) =
-  g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
-
-proc addAnnotation*(g: var TypeGraph; name: string) =
-  g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
-
-proc addField*(g: var TypeGraph; name: string; typ: TypeId; offset: int64) =
-  let f = g.openType FieldDecl
-  g.addType typ
-  g.addOffset offset
-  g.addName name
-  sealType(g, f)
-
-proc ptrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
-  let f = g.openType APtrTy
-  g.addType t
-  result = finishType(g, f)
-
-proc arrayPtrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
-  let f = g.openType AArrayPtrTy
-  g.addType t
-  result = finishType(g, f)
-
-proc store*(r: var RodFile; g: TypeGraph) =
-  storeSeq r, g.nodes
-
-proc load*(r: var RodFile; g: var TypeGraph) =
-  loadSeq r, g.nodes
-
-proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
-  case g[i].kind
-  of VoidTy: dest.add "void"
-  of IntTy:
-    dest.add "i"
-    dest.addInt g[i].operand
-  of UIntTy:
-    dest.add "u"
-    dest.addInt g[i].operand
-  of FloatTy:
-    dest.add "f"
-    dest.addInt g[i].operand
-  of BoolTy:
-    dest.add "b"
-    dest.addInt g[i].operand
-  of CharTy:
-    dest.add "c"
-    dest.addInt g[i].operand
-  of NameVal, AnnotationVal:
-    dest.add g.lit.strings[LitId g[i].operand]
-  of IntVal, SizeVal, AlignVal, OffsetVal:
-    dest.add $g[i].kind
-    dest.add ' '
-    dest.add $g.lit.numbers[LitId g[i].operand]
-  of VarargsTy:
-    dest.add "..."
-  of APtrTy:
-    dest.add "aptr["
-    toString(dest, g, g.elementType(i))
-    dest.add "]"
-  of UPtrTy:
-    dest.add "uptr["
-    toString(dest, g, g.elementType(i))
-    dest.add "]"
-  of AArrayPtrTy:
-    dest.add "aArrayPtr["
-    toString(dest, g, g.elementType(i))
-    dest.add "]"
-  of UArrayPtrTy:
-    dest.add "uArrayPtr["
-    toString(dest, g, g.elementType(i))
-    dest.add "]"
-  of ArrayTy:
-    dest.add "Array["
-    let (elems, len, name) = g.sons3(i)
-    toString(dest, g, elems)
-    dest.add ", "
-    toString(dest, g, len)
-    dest.add ", "
-    toString(dest, g, name)
-    dest.add "]"
-  of LastArrayTy:
-    # array of unspecified size as a last field inside an object
-    dest.add "LastArrayTy["
-    toString(dest, g, g.elementType(i))
-    dest.add "]"
-  of ObjectTy:
-    dest.add "object "
-    dest.add g.lit.strings[LitId g[i].operand]
-  of UnionTy:
-    dest.add "union "
-    dest.add g.lit.strings[LitId g[i].operand]
-  of ProcTy:
-    dest.add "proc["
-    for t in sons(g, i):
-      dest.add ' '
-      toString(dest, g, t)
-    dest.add "]"
-  of ObjectDecl:
-    dest.add "object["
-    for t in sons(g, i):
-      toString(dest, g, t)
-      dest.add '\n'
-    dest.add "]"
-  of UnionDecl:
-    dest.add "union["
-    for t in sons(g, i):
-      toString(dest, g, t)
-      dest.add '\n'
-    dest.add "]"
-  of FieldDecl:
-    dest.add "field["
-    for t in sons(g, i):
-      toString(dest, g, t)
-      dest.add ' '
-    dest.add "]"
-
-    when false:
-      let (typ, offset, name) = g.sons3(i)
-      toString(dest, g, typ)
-      dest.add ' '
-      toString(dest, g, offset)
-      dest.add ' '
-      toString(dest, g, name)
-
-proc toString*(dest: var string; g: TypeGraph) =
-  var i = 0
-  while i < g.len:
-    dest.add "T<"
-    dest.addInt i
-    dest.add "> "
-    toString(dest, g, TypeId i)
-    dest.add '\n'
-    nextChild g, i
-
-iterator allTypes*(g: TypeGraph; start = 0): TypeId =
-  var i = start
-  while i < g.len:
-    yield TypeId i
-    nextChild g, i
-
-iterator allTypesIncludingInner*(g: TypeGraph; start = 0): TypeId =
-  var i = start
-  while i < g.len:
-    yield TypeId i
-    inc i
-
-proc `$`(g: TypeGraph): string =
-  result = ""
-  toString(result, g)
-
-when isMainModule:
-  var g = initTypeGraph(Literals())
-
-  let a = g.openType ArrayTy
-  g.addBuiltinType Int8Id
-  g.addArrayLen 5
-  g.addName "SomeArray"
-  let finalArrayType = finishType(g, a)
-
-  let obj = g.openType ObjectDecl
-  g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl("MyType")))
-
-  g.addField "p", finalArrayType, 0
-  sealType(g, obj)
-
-  echo g
diff --git a/compiler/nir/nirvm.nim b/compiler/nir/nirvm.nim
deleted file mode 100644
index faa7a1fb7..000000000
--- a/compiler/nir/nirvm.nim
+++ /dev/null
@@ -1,1175 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-##[ NIR is a little too high level to interpret it efficiently. Thus
-we compute `addresses` for SymIds, labels and offsets for object fields
-in a preprocessing step.
-
-We also split the instruction stream into separate (code, debug) seqs while
-we're at it.
-]##
-
-import std / [syncio, assertions, tables, intsets]
-import ".." / ic / bitabs
-import nirinsts, nirtypes, nirfiles, nirlineinfos
-
-type
-  OpcodeM = enum
-    ImmediateValM,
-    IntValM,
-    StrValM,
-    LoadLocalM, # with local ID
-    LoadGlobalM,
-    LoadProcM,
-    TypedM,   # with type ID
-    PragmaIdM, # with Pragma ID, possible values: see PragmaKey enum
-    NilValM,
-    AllocLocals,
-    SummonParamM,
-    GotoM,
-    CheckedGotoM, # last atom
-
-    ArrayConstrM,
-    ObjConstrM,
-    RetM,
-    YldM,
-
-    SelectM,
-    SelectPairM,  # ((values...), Label)
-    SelectListM,  # (values...)
-    SelectValueM, # (value)
-    SelectRangeM, # (valueA..valueB)
-
-    AddrOfM,
-    ArrayAtM, # (elemSize, addr(a), i)
-    DerefArrayAtM,
-    FieldAtM, # addr(obj.field)
-    DerefFieldAtM,
-
-    LoadM, # a[]
-    AsgnM,  # a = b
-    StoreM, # a[] = b
-    SetExcM,
-    TestExcM,
-
-    CheckedRangeM,
-    CheckedIndexM,
-
-    CallM,
-    CheckedAddM, # with overflow checking etc.
-    CheckedSubM,
-    CheckedMulM,
-    CheckedDivM,
-    CheckedModM,
-    AddM,
-    SubM,
-    MulM,
-    DivM,
-    ModM,
-    BitShlM,
-    BitShrM,
-    BitAndM,
-    BitOrM,
-    BitXorM,
-    BitNotM,
-    BoolNotM,
-    EqM,
-    LeM,
-    LtM,
-    CastM,
-    NumberConvM,
-    CheckedObjConvM,
-    ObjConvM,
-    TestOfM,
-    ProcDeclM,
-    PragmaPairM
-
-const
-  LastAtomicValue = CheckedGotoM
-
-  OpcodeBits = 8'u32
-  OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
-
-type
-  Instr = distinct uint32
-
-template kind(n: Instr): OpcodeM = OpcodeM(n.uint32 and OpcodeMask)
-template operand(n: Instr): uint32 = (n.uint32 shr OpcodeBits)
-
-template toIns(k: OpcodeM; operand: uint32): Instr =
-  Instr(uint32(k) or (operand shl OpcodeBits))
-
-template toIns(k: OpcodeM; operand: LitId): Instr =
-  Instr(uint32(k) or (operand.uint32 shl OpcodeBits))
-
-type
-  NimStrPayloadVM = object
-    cap: int
-    data: UncheckedArray[char]
-  NimStringVM = object
-    len: int
-    p: ptr NimStrPayloadVM
-
-const
-  GlobalsSize = 1024*24
-
-type
-  PatchPos = distinct int
-  CodePos = distinct int
-
-  Bytecode* = object
-    code: seq[Instr]
-    debug: seq[PackedLineInfo]
-    m: ref NirModule
-    procs: Table[SymId, CodePos]
-    globals: Table[SymId, (uint32, int)]
-    strings: Table[LitId, NimStringVM]
-    globalData: pointer
-    globalsAddr: uint32
-    typeImpls: Table[string, TypeId]
-    offsets: Table[TypeId, seq[(int, TypeId)]]
-    sizes: Table[TypeId, (int, int)] # (size, alignment)
-    oldTypeLen: int
-    procUsagesToPatch: Table[SymId, seq[CodePos]]
-    interactive*: bool
-
-  Universe* = object ## all units: For interpretation we need that
-    units: seq[Bytecode]
-    unitNames: Table[string, int]
-    current: int
-
-proc initBytecode*(m: ref NirModule): Bytecode = Bytecode(m: m, globalData: alloc0(GlobalsSize))
-
-proc debug(bc: Bytecode; t: TypeId) =
-  var buf = ""
-  toString buf, bc.m.types, t
-  echo buf
-
-proc debug(bc: Bytecode; info: PackedLineInfo) =
-  let (litId, line, col) = bc.m.man.unpack(info)
-  echo bc.m.lit.strings[litId], ":", line, ":", col
-
-proc debug(bc: Bytecode; t: Tree; n: NodePos) =
-  var buf = ""
-  toString(t, n, bc.m.lit.strings, bc.m.lit.numbers, bc.m.symnames, buf)
-  echo buf
-
-template `[]`(t: seq[Instr]; n: CodePos): Instr = t[n.int]
-
-proc traverseObject(b: var Bytecode; t, offsetKey: TypeId) =
-  var size = -1
-  var align = -1
-  for x in sons(b.m.types, t):
-    case b.m.types[x].kind
-    of FieldDecl:
-      var offset = -1
-      for y in sons(b.m.types, x):
-        if b.m.types[y].kind == OffsetVal:
-          offset = int(b.m.lit.numbers[b.m.types[y].litId])
-          break
-      b.offsets.mgetOrPut(offsetKey, @[]).add (offset, x.firstSon)
-    of SizeVal:
-      size = int(b.m.lit.numbers[b.m.types[x].litId])
-    of AlignVal:
-      align = int(b.m.lit.numbers[b.m.types[x].litId])
-    of ObjectTy:
-      # inheritance
-      let impl = b.typeImpls.getOrDefault(b.m.lit.strings[b.m.types[x].litId])
-      assert impl.int > 0
-      traverseObject b, impl, offsetKey
-    else: discard
-  if t == offsetKey:
-    b.sizes[t] = (size, align)
-
-proc computeSize(b: var Bytecode; t: TypeId): (int, int) =
-  case b.m.types[t].kind
-  of ObjectDecl, UnionDecl:
-    result = b.sizes[t]
-  of ObjectTy, UnionTy:
-    let impl = b.typeImpls[b.m.lit.strings[b.m.types[t].litId]]
-    result = computeSize(b, impl)
-  of IntTy, UIntTy, FloatTy, BoolTy, CharTy:
-    let s = b.m.types[t].integralBits div 8
-    result = (s, s)
-  of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ProcTy:
-    result = (sizeof(pointer), sizeof(pointer))
-  of ArrayTy:
-    let e = elementType(b.m.types, t)
-    let n = arrayLen(b.m.types, t)
-    let inner = computeSize(b, e)
-    result = (inner[0] * n.int, inner[1])
-  else:
-    result = (0, 0)
-
-proc computeElemSize(b: var Bytecode; t: TypeId): int =
-  case b.m.types[t].kind
-  of ArrayTy, APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, LastArrayTy:
-    result = computeSize(b, elementType(b.m.types, t))[0]
-  else:
-    raiseAssert "not an array type"
-
-proc traverseTypes(b: var Bytecode) =
-  for t in allTypes(b.m.types, b.oldTypeLen):
-    if b.m.types[t].kind in {ObjectDecl, UnionDecl}:
-      assert b.m.types[t.firstSon].kind == NameVal
-      b.typeImpls[b.m.lit.strings[b.m.types[t.firstSon].litId]] = t
-
-  for t in allTypes(b.m.types, b.oldTypeLen):
-    if b.m.types[t].kind in {ObjectDecl, UnionDecl}:
-      assert b.m.types[t.firstSon].kind == NameVal
-      traverseObject b, t, t
-  b.oldTypeLen = b.m.types.len
-
-const
-  InvalidPatchPos* = PatchPos(-1)
-
-proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
-
-proc prepare(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM): PatchPos =
-  result = PatchPos bc.code.len
-  bc.code.add toIns(kind, 1'u32)
-  bc.debug.add info
-
-proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; raw: uint32) =
-  bc.code.add toIns(kind, raw)
-  bc.debug.add info
-
-proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; lit: LitId) =
-  add bc, info, kind, uint32(lit)
-
-proc isAtom(bc: Bytecode; pos: int): bool {.inline.} = bc.code[pos].kind <= LastAtomicValue
-proc isAtom(bc: Bytecode; pos: CodePos): bool {.inline.} = bc.code[pos.int].kind <= LastAtomicValue
-
-proc patch(bc: var Bytecode; pos: PatchPos) =
-  let pos = pos.int
-  let k = bc.code[pos].kind
-  assert k > LastAtomicValue
-  let distance = int32(bc.code.len - pos)
-  assert distance > 0
-  bc.code[pos] = toIns(k, cast[uint32](distance))
-
-template build(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; body: untyped) =
-  let pos = prepare(bc, info, kind)
-  body
-  patch(bc, pos)
-
-proc len*(bc: Bytecode): int {.inline.} = bc.code.len
-
-template rawSpan(n: Instr): int = int(operand(n))
-
-proc nextChild(bc: Bytecode; pos: var int) {.inline.} =
-  if bc.code[pos].kind > LastAtomicValue:
-    assert bc.code[pos].operand > 0'u32
-    inc pos, bc.code[pos].rawSpan
-  else:
-    inc pos
-
-proc next(bc: Bytecode; pos: var CodePos) {.inline.} = nextChild bc, int(pos)
-
-iterator sons(bc: Bytecode; n: CodePos): CodePos =
-  var pos = n.int
-  assert bc.code[pos].kind > LastAtomicValue
-  let last = pos + bc.code[pos].rawSpan
-  inc pos
-  while pos < last:
-    yield CodePos pos
-    nextChild bc, pos
-
-iterator sonsFrom1(bc: Bytecode; n: CodePos): CodePos =
-  var pos = n.int
-  assert bc.code[pos].kind > LastAtomicValue
-  let last = pos + bc.code[pos].rawSpan
-  inc pos
-  nextChild bc, pos
-  while pos < last:
-    yield CodePos pos
-    nextChild bc, pos
-
-iterator sonsFrom2(bc: Bytecode; n: CodePos): CodePos =
-  var pos = n.int
-  assert bc.code[pos].kind > LastAtomicValue
-  let last = pos + bc.code[pos].rawSpan
-  inc pos
-  nextChild bc, pos
-  nextChild bc, pos
-  while pos < last:
-    yield CodePos pos
-    nextChild bc, pos
-
-template firstSon(n: CodePos): CodePos = CodePos(n.int+1)
-
-template `[]`(t: Bytecode; n: CodePos): Instr = t.code[n.int]
-
-proc span(bc: Bytecode; pos: int): int {.inline.} =
-  if bc.code[pos].kind <= LastAtomicValue: 1 else: int(bc.code[pos].operand)
-
-iterator triples*(bc: Bytecode; n: CodePos): (uint32, int, CodePos) =
-  var pos = n.int
-  assert bc.code[pos].kind > LastAtomicValue
-  let last = pos + bc.code[pos].rawSpan
-  inc pos
-  while pos < last:
-    let offset = bc.code[pos].operand
-    nextChild bc, pos
-    let size = bc.code[pos].operand.int
-    nextChild bc, pos
-    let val = CodePos pos
-    yield (offset, size, val)
-    nextChild bc, pos
-
-proc toString*(t: Bytecode; pos: CodePos;
-               r: var string; nesting = 0) =
-  if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}:
-    r.add ' '
-
-  case t[pos].kind
-  of ImmediateValM:
-    r.add $t[pos].operand
-  of IntValM:
-    r.add "IntVal "
-    r.add $t.m.lit.numbers[LitId t[pos].operand]
-  of StrValM:
-    escapeToNimLit(t.m.lit.strings[LitId t[pos].operand], r)
-  of LoadLocalM, LoadGlobalM, LoadProcM, AllocLocals, SummonParamM:
-    r.add $t[pos].kind
-    r.add ' '
-    r.add $t[pos].operand
-  of PragmaIdM:
-    r.add $cast[PragmaKey](t[pos].operand)
-  of TypedM:
-    r.add "T<"
-    r.add $t[pos].operand
-    r.add ">"
-  of NilValM:
-    r.add "NilVal"
-  of GotoM, CheckedGotoM:
-    r.add $t[pos].kind
-    r.add " L"
-    r.add $t[pos].operand
-  else:
-    r.add $t[pos].kind
-    r.add "{\n"
-    for i in 0..<(nesting+1)*2: r.add ' '
-    for p in sons(t, pos):
-      toString t, p, r, nesting+1
-    r.add "\n"
-    for i in 0..<nesting*2: r.add ' '
-    r.add "}"
-
-proc debug(b: Bytecode; pos: CodePos) =
-  var buf = ""
-  toString(b, pos, buf)
-  echo buf
-
-type
-  Preprocessing = object
-    u: ref Universe
-    known: Table[LabelId, CodePos]
-    toPatch: Table[LabelId, seq[CodePos]]
-    locals: Table[SymId, (uint32, int)] # address, size
-    thisModule: uint32
-    localsAddr: uint32
-    markedWithLabel: IntSet
-
-proc align(address, alignment: uint32): uint32 =
-  result = (address + (alignment - 1'u32)) and not (alignment - 1'u32)
-
-proc genGoto(c: var Preprocessing; bc: var Bytecode; info: PackedLineInfo; lab: LabelId; opc: OpcodeM) =
-  let dest = c.known.getOrDefault(lab, CodePos(-1))
-  if dest.int >= 0:
-    bc.add info, opc, uint32 dest
-  else:
-    let here = CodePos(bc.code.len)
-    c.toPatch.mgetOrPut(lab, @[]).add here
-    bc.add info, opc, 1u32 # will be patched once we traversed the label
-
-type
-  AddrMode = enum
-    InDotExpr, WantAddr
-
-template maybeDeref(doDeref: bool; size: int; body: untyped) =
-  var pos = PatchPos(-1)
-  if doDeref:
-    pos = prepare(bc, info, LoadM)
-    bc.add info, ImmediateValM, uint32 size
-  body
-  if doDeref:
-    patch(bc, pos)
-
-proc toReadonlyString(s: string): NimStringVM =
-  if s.len == 0:
-    result = NimStringVM(len: 0, p: nil)
-  else:
-    result = NimStringVM(len: s.len, p: cast[ptr NimStrPayloadVM](alloc(s.len+1+sizeof(int))))
-    copyMem(addr result.p.data[0], addr s[0], s.len+1)
-    result.p.cap = s.len or (1 shl (8 * 8 - 2)) # see also NIM_STRLIT_FLAG
-
-const
-  ForwardedProc = 10_000_000'u32
-
-proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; flags: set[AddrMode]) =
-  let info = t[n].info
-
-  template recurse(opc) =
-    build bc, info, opc:
-      for ch in sons(t, n): preprocess(c, bc, t, ch, {WantAddr})
-
-  case t[n].kind
-  of Nop, ForeignDecl, ForeignProcDecl:
-    discard "don't use Nop"
-  of ImmediateVal:
-    bc.add info, ImmediateValM, t[n].rawOperand
-  of IntVal:
-    bc.add info, IntValM, t[n].rawOperand
-  of StrVal:
-    let litId = LitId t[n].rawOperand
-    if not bc.strings.hasKey(litId):
-      bc.strings[litId] = toReadonlyString(bc.m.lit.strings[litId])
-    bc.add info, StrValM, t[n].rawOperand
-  of SymDef:
-    discard "happens for proc decls. Don't copy the node as we don't need it"
-  of SymUse:
-    let s = t[n].symId
-    if c.locals.hasKey(s):
-      let (address, size) = c.locals[s]
-      maybeDeref(WantAddr notin flags, size):
-        bc.add info, LoadLocalM, address
-    elif bc.procs.hasKey(s):
-      bc.add info, LoadProcM, uint32 bc.procs[s]
-    elif bc.globals.hasKey(s):
-      let (address, size) = bc.globals[s]
-      maybeDeref(WantAddr notin flags, size):
-        bc.add info, LoadGlobalM, address
-    else:
-      let here = CodePos(bc.code.len)
-      bc.add info, LoadProcM, ForwardedProc + uint32(s)
-      bc.procUsagesToPatch.mgetOrPut(s, @[]).add here
-      #raiseAssert "don't understand SymUse ID " & $int(s)
-
-  of ModuleSymUse:
-    when false:
-      let (x, y) = sons2(t, n)
-      let unit = c.u.unitNames.getOrDefault(bc.m.lit.strings[t[x].litId], -1)
-      let s = t[y].symId
-      if c.u.units[unit].procs.hasKey(s):
-        bc.add info, LoadProcM, uint32 c.u.units[unit].procs[s]
-      elif bc.globals.hasKey(s):
-        maybeDeref(WantAddr notin flags):
-          build bc, info, LoadGlobalM:
-            bc.add info, ImmediateValM, uint32 unit
-            bc.add info, LoadLocalM, uint32 s
-      else:
-        raiseAssert "don't understand ModuleSymUse ID"
-
-    raiseAssert "don't understand ModuleSymUse ID"
-  of Typed:
-    bc.add info, TypedM, t[n].rawOperand
-  of PragmaId:
-    bc.add info, PragmaIdM, t[n].rawOperand
-  of NilVal:
-    bc.add info, NilValM, t[n].rawOperand
-  of LoopLabel, Label:
-    let lab = t[n].label
-    let here = CodePos(bc.code.len)
-    c.known[lab] = here
-    var p: seq[CodePos] = @[]
-    if c.toPatch.take(lab, p):
-      for x in p: (bc.code[x]) = toIns(bc.code[x].kind, uint32 here)
-    c.markedWithLabel.incl here.int # for toString()
-  of Goto, GotoLoop:
-    c.genGoto(bc, info, t[n].label, GotoM)
-  of CheckedGoto:
-    c.genGoto(bc, info, t[n].label, CheckedGotoM)
-  of ArrayConstr:
-    let typ = t[n.firstSon].typeId
-    let s = computeElemSize(bc, typ)
-    build bc, info, ArrayConstrM:
-      bc.add info, ImmediateValM, uint32 s
-      for ch in sonsFrom1(t, n):
-        preprocess(c, bc, t, ch, {WantAddr})
-  of ObjConstr:
-    #debug bc, t, n
-    var i = 0
-    let typ = t[n.firstSon].typeId
-    build bc, info, ObjConstrM:
-      for ch in sons(t, n):
-        if i > 0:
-          if (i mod 2) == 1:
-            let (offset, typ) = bc.offsets[typ][t[ch].immediateVal]
-            let size = computeSize(bc, typ)[0]
-            bc.add info, ImmediateValM, uint32(offset)
-            bc.add info, ImmediateValM, uint32(size)
-          else:
-            preprocess(c, bc, t, ch, {WantAddr})
-        inc i
-  of Ret:
-    recurse RetM
-  of Yld:
-    recurse YldM
-  of Select:
-    recurse SelectM
-  of SelectPair:
-    recurse SelectPairM
-  of SelectList:
-    recurse SelectListM
-  of SelectValue:
-    recurse SelectValueM
-  of SelectRange:
-    recurse SelectRangeM
-  of SummonGlobal, SummonThreadLocal, SummonConst:
-    let (typ, sym) = sons2(t, n)
-
-    let s = t[sym].symId
-    let tid = t[typ].typeId
-    let (size, alignment) = computeSize(bc, tid)
-
-    let global = align(bc.globalsAddr, uint32 alignment)
-    bc.globals[s] = (global, size)
-    bc.globalsAddr += uint32 size
-    assert bc.globalsAddr < GlobalsSize
-
-  of Summon:
-    let (typ, sym) = sons2(t, n)
-
-    let s = t[sym].symId
-    let tid = t[typ].typeId
-    let (size, alignment) = computeSize(bc, tid)
-
-    let local = align(c.localsAddr, uint32 alignment)
-    c.locals[s] = (local, size)
-    c.localsAddr += uint32 size
-    # allocation is combined into the frame allocation so there is no
-    # instruction to emit
-  of SummonParam, SummonResult:
-    let (typ, sym) = sons2(t, n)
-
-    let s = t[sym].symId
-    let tid = t[typ].typeId
-    let (size, alignment) = computeSize(bc, tid)
-
-    let local = align(c.localsAddr, uint32 alignment)
-    c.locals[s] = (local, size)
-    c.localsAddr += uint32 size
-    bc.add info, SummonParamM, local
-    bc.add info, ImmediateValM, uint32 size
-  of Kill:
-    discard "we don't care about Kill instructions"
-  of AddrOf:
-    let (_, arg) = sons2(t, n)
-    preprocess(c, bc, t, arg, {WantAddr})
-    # the address of x is what the VM works with all the time so there is
-    # nothing to compute.
-  of ArrayAt:
-    let (arrayType, a, i) = sons3(t, n)
-    let tid = t[arrayType].typeId
-    let size = uint32 computeElemSize(bc, tid)
-    build bc, info, ArrayAtM:
-      bc.add info, ImmediateValM, size
-      preprocess(c, bc, t, a, {WantAddr})
-      preprocess(c, bc, t, i, {WantAddr})
-  of DerefArrayAt:
-    let (arrayType, a, i) = sons3(t, n)
-    let tid = t[arrayType].typeId
-    let size = uint32 computeElemSize(bc, tid)
-    build bc, info, DerefArrayAtM:
-      bc.add info, ImmediateValM, size
-      preprocess(c, bc, t, a, {WantAddr})
-      preprocess(c, bc, t, i, {WantAddr})
-  of FieldAt:
-    let (typ, a, b) = sons3(t, n)
-    let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0]
-    build bc, info, FieldAtM:
-      preprocess(c, bc, t, a, flags+{WantAddr})
-      bc.add info, ImmediateValM, uint32(offset)
-  of DerefFieldAt:
-    let (typ, a, b) = sons3(t, n)
-    let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0]
-    build bc, info, DerefFieldAtM:
-      preprocess(c, bc, t, a, flags+{WantAddr})
-      bc.add info, ImmediateValM, uint32(offset)
-  of Load:
-    let (elemType, a) = sons2(t, n)
-    let tid = t[elemType].typeId
-    build bc, info, LoadM:
-      bc.add info, ImmediateValM, uint32 computeSize(bc, tid)[0]
-      preprocess(c, bc, t, a, {})
-
-  of Store:
-    raiseAssert "Assumption was that Store is unused!"
-  of Asgn:
-    let (elemType, dest, src) = sons3(t, n)
-    let tid = t[elemType].typeId
-    if t[src].kind in {Call, IndirectCall}:
-      # No support for return values, these are mapped to `var T` parameters!
-      build bc, info, CallM:
-        preprocess(c, bc, t, src.skipTyped, {WantAddr})
-        preprocess(c, bc, t, dest, {WantAddr})
-        for ch in sonsFromN(t, src, 2): preprocess(c, bc, t, ch, {WantAddr})
-    elif t[src].kind in {CheckedCall, CheckedIndirectCall}:
-      let (_, gotoInstr, fn) = sons3(t, src)
-      build bc, info, CallM:
-        preprocess(c, bc, t, fn, {WantAddr})
-        preprocess(c, bc, t, dest, {WantAddr})
-        for ch in sonsFromN(t, src, 3): preprocess(c, bc, t, ch, {WantAddr})
-      preprocess c, bc, t, gotoInstr, {}
-    elif t[dest].kind == Load:
-      let (typ, a) = sons2(t, dest)
-      let s = computeSize(bc, tid)[0]
-      build bc, info, StoreM:
-        bc.add info, ImmediateValM, uint32 s
-        preprocess(c, bc, t, a, {WantAddr})
-        preprocess(c, bc, t, src, {})
-    else:
-      let s = computeSize(bc, tid)[0]
-      build bc, info, AsgnM:
-        bc.add info, ImmediateValM, uint32 s
-        preprocess(c, bc, t, dest, {WantAddr})
-        preprocess(c, bc, t, src, {})
-  of SetExc:
-    recurse SetExcM
-  of TestExc:
-    recurse TestExcM
-  of CheckedRange:
-    recurse CheckedRangeM
-  of CheckedIndex:
-    recurse CheckedIndexM
-  of Call, IndirectCall:
-    # avoid the Typed thing at position 0:
-    build bc, info, CallM:
-      for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr})
-  of CheckedCall, CheckedIndirectCall:
-    # avoid the Typed thing at position 0:
-    let (_, gotoInstr, fn) = sons3(t, n)
-    build bc, info, CallM:
-      preprocess(c, bc, t, fn, {WantAddr})
-      for ch in sonsFromN(t, n, 3): preprocess(c, bc, t, ch, {WantAddr})
-    preprocess c, bc, t, gotoInstr, {WantAddr}
-  of CheckedAdd:
-    recurse CheckedAddM
-  of CheckedSub:
-    recurse CheckedSubM
-  of CheckedMul:
-    recurse CheckedMulM
-  of CheckedDiv:
-    recurse CheckedDivM
-  of CheckedMod:
-    recurse CheckedModM
-  of Add:
-    recurse AddM
-  of Sub:
-    recurse SubM
-  of Mul:
-    recurse MulM
-  of Div:
-    recurse DivM
-  of Mod:
-    recurse ModM
-  of BitShl:
-    recurse BitShlM
-  of BitShr:
-    recurse BitShrM
-  of BitAnd:
-    recurse BitAndM
-  of BitOr:
-    recurse BitOrM
-  of BitXor:
-    recurse BitXorM
-  of BitNot:
-    recurse BitNotM
-  of BoolNot:
-    recurse BoolNotM
-  of Eq:
-    recurse EqM
-  of Le:
-    recurse LeM
-  of Lt:
-    recurse LtM
-  of Cast:
-    recurse CastM
-  of NumberConv:
-    recurse NumberConvM
-  of CheckedObjConv:
-    recurse CheckedObjConvM
-  of ObjConv:
-    recurse ObjConvM
-  of TestOf:
-    recurse TestOfM
-  of Emit:
-    raiseAssert "cannot interpret: Emit"
-  of ProcDecl:
-    var c2 = Preprocessing(u: c.u, thisModule: c.thisModule)
-    let sym = t[n.firstSon].symId
-    let here = CodePos(bc.len)
-    var p: seq[CodePos] = @[]
-    if bc.procUsagesToPatch.take(sym, p):
-      for x in p: (bc.code[x]) = toIns(bc.code[x].kind, uint32 here)
-    bc.procs[sym] = here
-    build bc, info, ProcDeclM:
-      let toPatch = bc.code.len
-      bc.add info, AllocLocals, 0'u32
-      for ch in sons(t, n): preprocess(c2, bc, t, ch, {})
-      bc.code[toPatch] = toIns(AllocLocals, c2.localsAddr)
-    when false:
-      if here.int == 39850:
-        debug bc, t, n
-        debug bc, here
-
-  of PragmaPair:
-    recurse PragmaPairM
-
-const PayloadSize = 128
-
-type
-  StackFrame = ref object
-    locals: pointer   # usually points into `payload` if size is small enough, otherwise it's `alloc`'ed.
-    payload: array[PayloadSize, byte]
-    caller: StackFrame
-    returnAddr: CodePos
-    jumpTo: CodePos # exception handling
-    u: ref Universe
-
-proc newStackFrame(size: int; caller: StackFrame; returnAddr: CodePos): StackFrame =
-  result = StackFrame(caller: caller, returnAddr: returnAddr, u: caller.u)
-  if size <= PayloadSize:
-    result.locals = addr(result.payload)
-  else:
-    result.locals = alloc0(size)
-
-proc popStackFrame(s: StackFrame): StackFrame =
-  if s.locals != addr(s.payload):
-    dealloc s.locals
-  result = s.caller
-
-template `+!`(p: pointer; diff: uint): pointer = cast[pointer](cast[uint](p) + diff)
-
-proc isAtom(tree: seq[Instr]; pos: CodePos): bool {.inline.} = tree[pos.int].kind <= LastAtomicValue
-
-proc span(bc: seq[Instr]; pos: int): int {.inline.} =
-  if bc[pos].kind <= LastAtomicValue: 1 else: int(bc[pos].operand)
-
-proc sons2(tree: seq[Instr]; n: CodePos): (CodePos, CodePos) =
-  assert(not isAtom(tree, n))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  result = (CodePos a, CodePos b)
-
-proc sons3(tree: seq[Instr]; n: CodePos): (CodePos, CodePos, CodePos) =
-  assert(not isAtom(tree, n))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  result = (CodePos a, CodePos b, CodePos c)
-
-proc sons4(tree: seq[Instr]; n: CodePos): (CodePos, CodePos, CodePos, CodePos) =
-  assert(not isAtom(tree, n))
-  let a = n.int+1
-  let b = a + span(tree, a)
-  let c = b + span(tree, b)
-  let d = c + span(tree, c)
-  result = (CodePos a, CodePos b, CodePos c, CodePos d)
-
-proc typeId*(ins: Instr): TypeId {.inline.} =
-  assert ins.kind == TypedM
-  result = TypeId(ins.operand)
-
-proc immediateVal*(ins: Instr): int {.inline.} =
-  assert ins.kind == ImmediateValM
-  result = cast[int](ins.operand)
-
-proc litId*(ins: Instr): LitId {.inline.} =
-  assert ins.kind in {StrValM, IntValM}
-  result = LitId(ins.operand)
-
-proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int)
-
-proc evalAddr(c: Bytecode; pc: CodePos; s: StackFrame): pointer =
-  case c.code[pc].kind
-  of LoadLocalM:
-    result = s.locals +! c.code[pc].operand
-  of FieldAtM:
-    let (x, offset) = sons2(c.code, pc)
-    result = evalAddr(c, x, s)
-    result = result +! c.code[offset].operand
-  of DerefFieldAtM:
-    let (x, offset) = sons2(c.code, pc)
-    let p = evalAddr(c, x, s)
-    result = cast[ptr pointer](p)[] +! c.code[offset].operand
-  of ArrayAtM:
-    let (e, a, i) = sons3(c.code, pc)
-    let elemSize = c.code[e].operand
-    result = evalAddr(c, a, s)
-    var idx: int = 0
-    eval(c, i, s, addr idx, sizeof(int))
-    result = result +! (uint32(idx) * elemSize)
-  of DerefArrayAtM:
-    let (e, a, i) = sons3(c.code, pc)
-    let elemSize = c.code[e].operand
-    var p = evalAddr(c, a, s)
-    var idx: int = 0
-    eval(c, i, s, addr idx, sizeof(int))
-    result = cast[ptr pointer](p)[] +! (uint32(idx) * elemSize)
-  of LoadGlobalM:
-    result = c.globalData +! c.code[pc].operand
-  else:
-    raiseAssert("unimplemented addressing mode")
-
-proc `div`(x, y: float32): float32 {.inline.} = x / y
-proc `div`(x, y: float64): float64 {.inline.} = x / y
-
-from std / math import `mod`
-
-template binop(opr) {.dirty.} =
-  template impl(typ) {.dirty.} =
-    var x = default(typ)
-    var y = default(typ)
-    eval c, a, s, addr x, sizeof(typ)
-    eval c, b, s, addr y, sizeof(typ)
-    cast[ptr typ](result)[] = opr(x, y)
-
-  let (t, a, b) = sons3(c.code, pc)
-  let tid = TypeId c.code[t].operand
-  case tid
-  of Bool8Id, Char8Id, UInt8Id: impl uint8
-  of Int8Id: impl int8
-  of Int16Id: impl int16
-  of Int32Id: impl int32
-  of Int64Id: impl int64
-  of UInt16Id: impl uint16
-  of UInt32Id: impl uint32
-  of UInt64Id: impl uint64
-  of Float32Id: impl float32
-  of Float64Id: impl float64
-  else: discard
-
-template checkedBinop(opr) {.dirty.} =
-  template impl(typ) {.dirty.} =
-    var x = default(typ)
-    var y = default(typ)
-    eval c, a, s, addr x, sizeof(typ)
-    eval c, b, s, addr y, sizeof(typ)
-    try:
-      cast[ptr typ](result)[] = opr(x, y)
-    except OverflowDefect, DivByZeroDefect:
-      s.jumpTo = CodePos c.code[j].operand
-
-  let (t, j, a, b) = sons4(c.code, pc)
-  let tid = TypeId c.code[t].operand
-  case tid
-  of Bool8Id, Char8Id, UInt8Id: impl uint8
-  of Int8Id: impl int8
-  of Int16Id: impl int16
-  of Int32Id: impl int32
-  of Int64Id: impl int64
-  of UInt16Id: impl uint16
-  of UInt32Id: impl uint32
-  of UInt64Id: impl uint64
-  of Float32Id: impl float32
-  of Float64Id: impl float64
-  else: discard
-
-template bitop(opr) {.dirty.} =
-  template impl(typ) {.dirty.} =
-    var x = default(typ)
-    var y = default(typ)
-    eval c, a, s, addr x, sizeof(typ)
-    eval c, b, s, addr y, sizeof(typ)
-    cast[ptr typ](result)[] = opr(x, y)
-
-  let (t, a, b) = sons3(c.code, pc)
-  let tid = c.code[t].typeId
-  case tid
-  of Bool8Id, Char8Id, UInt8Id: impl uint8
-  of Int8Id: impl int8
-  of Int16Id: impl int16
-  of Int32Id: impl int32
-  of Int64Id: impl int64
-  of UInt16Id: impl uint16
-  of UInt32Id: impl uint32
-  of UInt64Id: impl uint64
-  else: discard
-
-template cmpop(opr) {.dirty.} =
-  template impl(typ) {.dirty.} =
-    var x = default(typ)
-    var y = default(typ)
-    eval c, a, s, addr x, sizeof(typ)
-    eval c, b, s, addr y, sizeof(typ)
-    cast[ptr bool](result)[] = opr(x, y)
-
-  let (t, a, b) = sons3(c.code, pc)
-  let tid = c.code[t].typeId
-  case tid
-  of Bool8Id, Char8Id, UInt8Id: impl uint8
-  of Int8Id: impl int8
-  of Int16Id: impl int16
-  of Int32Id: impl int32
-  of Int64Id: impl int64
-  of UInt16Id: impl uint16
-  of UInt32Id: impl uint32
-  of UInt64Id: impl uint64
-  of Float32Id: impl float32
-  of Float64Id: impl float64
-  else: discard
-
-proc evalSelect(c: Bytecode; pc: CodePos; s: StackFrame): CodePos =
-  template impl(typ) {.dirty.} =
-    var selector = default(typ)
-    eval c, sel, s, addr selector, sizeof(typ)
-    for pair in sonsFrom2(c, pc):
-      assert c.code[pair].kind == SelectPairM
-      let (values, action) = sons2(c.code, pair)
-      if c.code[values].kind == SelectValueM:
-        var a = default(typ)
-        eval c, values.firstSon, s, addr a, sizeof(typ)
-        if selector == a:
-          return CodePos c.code[action].operand
-      else:
-        assert c.code[values].kind == SelectListM, $c.code[values].kind
-        for v in sons(c, values):
-          case c.code[v].kind
-          of SelectValueM:
-            var a = default(typ)
-            eval c, v.firstSon, s, addr a, sizeof(typ)
-            if selector == a:
-              return CodePos c.code[action].operand
-          of SelectRangeM:
-            let (va, vb) = sons2(c.code, v)
-            var a = default(typ)
-            eval c, va, s, addr a, sizeof(typ)
-            var b = default(typ)
-            eval c, vb, s, addr a, sizeof(typ)
-            if a <= selector and selector <= b:
-              return CodePos c.code[action].operand
-          else: raiseAssert "unreachable"
-    result = CodePos(-1)
-
-  let (t, sel) = sons2(c.code, pc)
-  let tid = c.code[t].typeId
-  case tid
-  of Bool8Id, Char8Id, UInt8Id: impl uint8
-  of Int8Id: impl int8
-  of Int16Id: impl int16
-  of Int32Id: impl int32
-  of Int64Id: impl int64
-  of UInt16Id: impl uint16
-  of UInt32Id: impl uint32
-  of UInt64Id: impl uint64
-  else: raiseAssert "unreachable"
-
-proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) =
-  case c.code[pc].kind
-  of LoadLocalM:
-    let src = s.locals +! c.code[pc].operand
-    copyMem result, src, size
-  of FieldAtM, DerefFieldAtM, ArrayAtM, DerefArrayAtM, LoadGlobalM:
-    let src = evalAddr(c, pc, s)
-    copyMem result, src, size
-  of LoadProcM:
-    let procAddr = c.code[pc].operand
-    cast[ptr pointer](result)[] = cast[pointer](procAddr)
-  of LoadM:
-    let (_, arg) = sons2(c.code, pc)
-    let src = evalAddr(c, arg, s)
-    copyMem result, src, size
-  of CheckedAddM: checkedBinop `+`
-  of CheckedSubM: checkedBinop `-`
-  of CheckedMulM: checkedBinop `*`
-  of CheckedDivM: checkedBinop `div`
-  of CheckedModM: checkedBinop `mod`
-  of AddM: binop `+`
-  of SubM: binop `-`
-  of MulM: binop `*`
-  of DivM: binop `div`
-  of ModM: binop `mod`
-  of BitShlM: bitop `shl`
-  of BitShrM: bitop `shr`
-  of BitAndM: bitop `and`
-  of BitOrM: bitop `or`
-  of BitXorM: bitop `xor`
-  of EqM: cmpop `==`
-  of LeM: cmpop `<=`
-  of LtM: cmpop `<`
-
-  of StrValM:
-    # binary compatible and no deep copy required:
-    copyMem(cast[ptr string](result), addr(c.strings[c[pc].litId]), sizeof(string))
-  of ObjConstrM:
-    for offset, size, val in triples(c, pc):
-      eval c, val, s, result+!offset, size
-  of ArrayConstrM:
-    let elemSize = c.code[pc.firstSon].operand
-    var r = result
-    for ch in sonsFrom1(c, pc):
-      eval c, ch, s, r, elemSize.int
-      r = r+!elemSize # can even do strength reduction here!
-  of NumberConvM:
-    let (t, x) = sons2(c.code, pc)
-    let word = if c[x].kind == NilValM: 0'i64 else: c.m.lit.numbers[c[x].litId]
-
-    template impl(typ: typedesc) {.dirty.} =
-      cast[ptr typ](result)[] = cast[typ](word)
-
-    let tid = c.code[t].typeId
-    case tid
-    of Bool8Id, Char8Id, UInt8Id: impl uint8
-    of Int8Id: impl int8
-    of Int16Id: impl int16
-    of Int32Id: impl int32
-    of Int64Id: impl int64
-    of UInt16Id: impl uint16
-    of UInt32Id: impl uint32
-    of UInt64Id: impl uint64
-    of Float32Id: impl float32
-    of Float64Id: impl float64
-    else:
-      case c.m.types[tid].kind
-      of ProcTy, UPtrTy, APtrTy, AArrayPtrTy, UArrayPtrTy:
-        # the VM always uses 64 bit pointers:
-        impl uint64
-      else:
-        raiseAssert "cannot happen: " & $c.m.types[tid].kind
-  else:
-    #debug c, c.debug[pc.int]
-    raiseAssert "cannot happen: " & $c.code[pc].kind
-
-proc evalProc(c: Bytecode; pc: CodePos; s: StackFrame): CodePos =
-  assert c.code[pc].kind == LoadProcM
-  let procSym = c[pc].operand
-  when false:
-    if procSym >= ForwardedProc:
-      for k, v in c.procUsagesToPatch:
-        if uint32(k) == procSym - ForwardedProc:
-          echo k.int, " ", v.len, " <-- this one"
-        else:
-          echo k.int, " ", v.len
-
-  assert procSym < ForwardedProc
-  result = CodePos(procSym)
-
-proc echoImpl(c: Bytecode; pc: CodePos; frame: StackFrame) =
-  var s = default(NimStringVM)
-  for a in sonsFrom1(c, pc):
-    assert c[a].kind == ArrayConstrM
-    let elemSize = c.code[a.firstSon].operand.int
-    for ch in sonsFrom1(c, a):
-      eval c, ch, frame, addr s, elemSize
-      if s.len > 0:
-        discard stdout.writeBuffer(addr(s.p.data[0]), s.len)
-  stdout.write "\n"
-  stdout.flushFile()
-
-type
-  EvalBuiltinState = enum
-    DidNothing, DidEval, DidError
-
-proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; state: var EvalBuiltinState): CodePos =
-  var prc = prc
-  while true:
-    case c[prc].kind
-    of PragmaPairM:
-      let (x, y) = sons2(c.code, prc)
-      let key = cast[PragmaKey](c[x].operand)
-      case key
-      of CoreName:
-        let lit = c[y].litId
-        case c.m.lit.strings[lit]
-        of "echoBinSafe": echoImpl(c, pc, s)
-        else:
-          raiseAssert "cannot eval: " & c.m.lit.strings[lit]
-        state = DidEval
-      of HeaderImport, DllImport:
-        let lit = c[y].litId
-        raiseAssert "cannot eval: " & c.m.lit.strings[lit]
-      else: discard
-    of PragmaIdM, AllocLocals: discard
-    else: break
-    next c, prc
-  result = prc
-
-proc exec(c: Bytecode; pc: CodePos; u: ref Universe) =
-  var pc = pc
-  var frame = StackFrame(u: u)
-  while pc.int < c.code.len:
-    when false: # c.interactive:
-      echo "running: ", pc.int
-      debug c, pc
-
-    case c.code[pc].kind
-    of GotoM:
-      pc = CodePos(c.code[pc].operand)
-    of AsgnM:
-      let (sz, a, b) = sons3(c.code, pc)
-      let dest = evalAddr(c, a, frame)
-      eval(c, b, frame, dest, c.code[sz].operand.int)
-      next c, pc
-    of StoreM:
-      let (sz, a, b) = sons3(c.code, pc)
-      let destPtr = evalAddr(c, a, frame)
-      let dest = cast[ptr pointer](destPtr)[]
-      eval(c, b, frame, dest, c.code[sz].operand.int)
-      next c, pc
-    of CallM:
-      # No support for return values, these are mapped to `var T` parameters!
-      var prc = evalProc(c, pc.firstSon, frame)
-      assert c.code[prc.firstSon].kind == AllocLocals
-      let frameSize = int c.code[prc.firstSon].operand
-      # skip stupid stuff:
-      var evalState = DidNothing
-      prc = evalBuiltin(c, pc, frame, prc.firstSon, evalState)
-      if evalState != DidNothing:
-        next c, pc
-        if pc.int < c.code.len and c.code[pc].kind == CheckedGotoM:
-          if evalState == DidEval:
-            next c, pc
-          else:
-            pc = CodePos(c.code[pc].operand)
-      else:
-        # setup storage for the proc already:
-        let callInstr = pc
-        next c, pc
-        let s2 = newStackFrame(frameSize, frame, pc)
-        for a in sonsFrom1(c, callInstr):
-          assert c[prc].kind == SummonParamM
-          let paramAddr = c[prc].operand
-          next c, prc
-          assert c[prc].kind == ImmediateValM
-          let paramSize = c[prc].operand.int
-          next c, prc
-          eval(c, a, s2, s2.locals +! paramAddr, paramSize)
-        frame = s2
-        pc = prc
-    of RetM:
-      pc = frame.returnAddr
-      if c.code[pc].kind == CheckedGotoM:
-        pc = frame.jumpTo
-      frame = popStackFrame(frame)
-    of SelectM:
-      let pc2 = evalSelect(c, pc, frame)
-      if pc2.int >= 0:
-        pc = pc2
-      else:
-        next c, pc
-    of ProcDeclM:
-      next c, pc
-    else:
-      #debug c, c.debug[pc.int]
-      raiseAssert "unreachable: " & $c.code[pc].kind
-
-proc execCode*(bc: var Bytecode; t: Tree; n: NodePos) =
-  traverseTypes bc
-  var c = Preprocessing(u: nil, thisModule: 1'u32)
-  let start = CodePos(bc.code.len)
-  var pc = n
-  while pc.int < t.len:
-    #if bc.interactive:
-    #  echo "RUnning: "
-    #  debug bc, t, pc
-    preprocess c, bc, t, pc, {}
-    next t, pc
-  exec bc, start, nil
diff --git a/compiler/nir/stringcases.nim b/compiler/nir/stringcases.nim
deleted file mode 100644
index afdf8fda4..000000000
--- a/compiler/nir/stringcases.nim
+++ /dev/null
@@ -1,200 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## included from ast2ir.nim
-
-#[
-
-case s
-of "abc", "abbd":
-  echo 1
-of "hah":
-  echo 2
-of "gah":
-  echo 3
-
-# we produce code like this:
-
-if s[0] <= 'a':
-  if s == "abc: goto L1
-  elif s == "abbd": goto L1
-else:
-  if s[2] <= 'h':
-    if s == "hah": goto L2
-    elif s == "gah": goto L3
-goto afterCase
-
-L1:
-  echo 1
-  goto afterCase
-L2:
-  echo 2
-  goto afterCase
-L3:
-  echo 3
-  goto afterCase
-
-afterCase: ...
-
-]#
-
-# We split the set of strings into 2 sets of roughly the same size.
-# The condition used for splitting is a (position, char) tuple.
-# Every string of length > position for which s[position] <= char is in one
-# set else it is in the other set.
-
-from std/sequtils import addUnique
-
-type
-  Key = (LitId, LabelId)
-
-proc splitValue(strings: BiTable[string]; a: openArray[Key]; position: int): (char, float) =
-  var cand: seq[char] = @[]
-  for t in items a:
-    let s = strings[t[0]]
-    if s.len > position: cand.addUnique s[position]
-
-  result = ('\0', -1.0)
-  for disc in items cand:
-    var hits = 0
-    for t in items a:
-      let s = strings[t[0]]
-      if s.len > position and s[position] <= disc:
-        inc hits
-    # the split is the better, the more `hits` is close to `a.len / 2`:
-    let grade = 100000.0 - abs(hits.float - a.len.float / 2.0)
-    if grade > result[1]:
-      result = (disc, grade)
-
-proc tryAllPositions(strings: BiTable[string]; a: openArray[Key]): (char, int) =
-  var m = 0
-  for t in items a:
-    m = max(m, strings[t[0]].len)
-
-  result = ('\0', -1)
-  var best = -1.0
-  for i in 0 ..< m:
-    let current = splitValue(strings, a, i)
-    if current[1] > best:
-      best = current[1]
-      result = (current[0], i)
-
-type
-  SearchKind = enum
-    LinearSearch, SplitSearch
-  SearchResult* = object
-    case kind: SearchKind
-    of LinearSearch:
-      a: seq[Key]
-    of SplitSearch:
-      span: int
-      best: (char, int)
-
-proc emitLinearSearch(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) =
-  var d = SearchResult(kind: LinearSearch, a: @[])
-  for x in a: d.a.add x
-  dest.add d
-
-proc split(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) =
-  if a.len <= 4:
-    emitLinearSearch strings, a, dest
-  else:
-    let best = tryAllPositions(strings, a)
-    var groupA: seq[Key] = @[]
-    var groupB: seq[Key] = @[]
-    for t in items a:
-      let s = strings[t[0]]
-      if s.len > best[1] and s[best[1]] <= best[0]:
-        groupA.add t
-      else:
-        groupB.add t
-    if groupA.len == 0 or groupB.len == 0:
-      emitLinearSearch strings, a, dest
-    else:
-      let toPatch = dest.len
-      dest.add SearchResult(kind: SplitSearch, span: 1, best: best)
-      split strings, groupA, dest
-      split strings, groupB, dest
-      let dist = dest.len - toPatch
-      assert dist > 0
-      dest[toPatch].span = dist
-
-proc toProblemDescription(c: var ProcCon; n: PNode): (seq[Key], LabelId) =
-  result = (@[], newLabels(c.labelGen, n.len))
-  assert n.kind == nkCaseStmt
-  for i in 1..<n.len:
-    let it = n[i]
-    let thisBranch = LabelId(result[1].int + i - 1)
-    if it.kind == nkOfBranch:
-      for j in 0..<it.len-1:
-        assert it[j].kind in {nkStrLit..nkTripleStrLit}
-        result[0].add (c.lit.strings.getOrIncl(it[j].strVal), thisBranch)
-
-proc decodeSolution(c: var ProcCon; dest: var Tree; s: seq[SearchResult]; i: int;
-                    selector: Value; info: PackedLineInfo) =
-  case s[i].kind
-  of SplitSearch:
-    let thenA = i+1
-    let elseA = thenA + (if s[thenA].kind == LinearSearch: 1 else: s[thenA].span)
-    let best = s[i].best
-
-    let tmp = getTemp(c, Bool8Id, info)
-    buildTyped dest, info, Asgn, Bool8Id:
-      dest.copyTree tmp
-      buildTyped dest, info, Call, Bool8Id:
-        c.addUseCodegenProc dest, "nimStrAtLe", info
-        dest.copyTree selector
-        dest.addIntVal c.lit.numbers, info, c.m.nativeIntId, best[1]
-        dest.addIntVal c.lit.numbers, info, Char8Id, best[0].int
-
-    template then() =
-      c.decodeSolution dest, s, thenA, selector, info
-    template otherwise() =
-      c.decodeSolution dest, s, elseA, selector, info
-    buildIfThenElse tmp, then, otherwise
-    freeTemp c, tmp
-
-  of LinearSearch:
-    let tmp = getTemp(c, Bool8Id, info)
-    for x in s[i].a:
-      buildTyped dest, info, Asgn, Bool8Id:
-        dest.copyTree tmp
-        buildTyped dest, info, Call, Bool8Id:
-          c.addUseCodegenProc dest, "eqStrings", info
-          dest.copyTree selector
-          dest.addStrLit info, x[0]
-      buildIf tmp:
-        c.code.gotoLabel info, Goto, x[1]
-    freeTemp c, tmp
-
-proc genStringCase(c: var ProcCon; n: PNode; d: var Value) =
-  let (problem, firstBranch) = toProblemDescription(c, n)
-  var solution: seq[SearchResult] = @[]
-  split c.lit.strings, problem, solution
-
-  # XXX Todo move complex case selector into a temporary.
-  let selector = c.genx(n[0])
-
-  let info = toLineInfo(c, n.info)
-  decodeSolution c, c.code, solution, 0, selector, info
-
-  let lend = newLabel(c.labelGen)
-  c.code.addLabel info, Goto, lend
-  for i in 1..<n.len:
-    let it = n[i]
-    let thisBranch = LabelId(firstBranch.int + i - 1)
-    c.code.addLabel info, Label, thisBranch
-    if it.kind == nkOfBranch:
-      gen(c, it.lastSon, d)
-      c.code.addLabel info, Goto, lend
-    else:
-      gen(c, it.lastSon, d)
-
-  c.code.addLabel info, Label, lend
-  freeTemp c, selector
diff --git a/compiler/nir/types2ir.nim b/compiler/nir/types2ir.nim
deleted file mode 100644
index 8d9583486..000000000
--- a/compiler/nir/types2ir.nim
+++ /dev/null
@@ -1,525 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2023 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-import std / [assertions, tables, sets]
-import ".." / [ast, types, options, sighashes, modulegraphs]
-import nirtypes
-
-type
-  TypesCon* = object
-    processed: Table[ItemId, TypeId]
-    processedByName: Table[string, TypeId]
-    recursionCheck: HashSet[ItemId]
-    conf: ConfigRef
-    stringType: TypeId
-
-proc initTypesCon*(conf: ConfigRef): TypesCon =
-  TypesCon(conf: conf, stringType: TypeId(-1))
-
-proc mangle(c: var TypesCon; t: PType): string =
-  result = $sighashes.hashType(t, c.conf)
-
-template cached(c: var TypesCon; t: PType; body: untyped) =
-  result = c.processed.getOrDefault(t.itemId)
-  if result.int == 0:
-    body
-    c.processed[t.itemId] = result
-
-template cachedByName(c: var TypesCon; t: PType; body: untyped) =
-  let key = mangle(c, t)
-  result = c.processedByName.getOrDefault(key)
-  if result.int == 0:
-    body
-    c.processedByName[key] = result
-
-proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId
-
-proc collectFieldTypes(c: var TypesCon; g: var TypeGraph; n: PNode; dest: var Table[ItemId, TypeId]) =
-  case n.kind
-  of nkRecList:
-    for i in 0..<n.len:
-      collectFieldTypes(c, g, n[i], dest)
-  of nkRecCase:
-    assert(n[0].kind == nkSym)
-    collectFieldTypes(c, g, n[0], dest)
-    for i in 1..<n.len:
-      case n[i].kind
-      of nkOfBranch, nkElse:
-        collectFieldTypes c, g, lastSon(n[i]), dest
-      else: discard
-  of nkSym:
-    dest[n.sym.itemId] = typeToIr(c, g, n.sym.typ)
-  else:
-    assert false, "unknown node kind: " & $n.kind
-
-proc objectToIr(c: var TypesCon; g: var TypeGraph; n: PNode; fieldTypes: Table[ItemId, TypeId]; unionId: var int) =
-  case n.kind
-  of nkRecList:
-    for i in 0..<n.len:
-      objectToIr(c, g, n[i], fieldTypes, unionId)
-  of nkRecCase:
-    assert(n[0].kind == nkSym)
-    objectToIr(c, g, n[0], fieldTypes, unionId)
-    let u = openType(g, UnionDecl)
-    g.addName "u_" & $unionId
-    inc unionId
-    for i in 1..<n.len:
-      case n[i].kind
-      of nkOfBranch, nkElse:
-        let subObj = openType(g, ObjectDecl)
-        g.addName "uo_" & $unionId & "_" & $i
-        objectToIr c, g, lastSon(n[i]), fieldTypes, unionId
-        sealType(g, subObj)
-      else: discard
-    sealType(g, u)
-  of nkSym:
-    g.addField n.sym.name.s & "_" & $n.sym.position, fieldTypes[n.sym.itemId], n.sym.offset
-  else:
-    assert false, "unknown node kind: " & $n.kind
-
-proc objectToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  if t.baseClass != nil:
-    # ensure we emitted the base type:
-    discard typeToIr(c, g, t.baseClass)
-
-  var unionId = 0
-  var fieldTypes = initTable[ItemId, TypeId]()
-  collectFieldTypes c, g, t.n, fieldTypes
-  let obj = openType(g, ObjectDecl)
-  g.addName mangle(c, t)
-  g.addSize c.conf.getSize(t)
-  g.addAlign c.conf.getAlign(t)
-
-  if t.baseClass != nil:
-    g.addNominalType(ObjectTy, mangle(c, t.baseClass))
-  else:
-    g.addBuiltinType VoidId # object does not inherit
-    if not lacksMTypeField(t):
-      let f2 = g.openType FieldDecl
-      let voidPtr = openType(g, APtrTy)
-      g.addBuiltinType(VoidId)
-      sealType(g, voidPtr)
-      g.addOffset 0 # type field is always at offset 0
-      g.addName "m_type"
-      sealType(g, f2) # FieldDecl
-
-  objectToIr c, g, t.n, fieldTypes, unionId
-  result = finishType(g, obj)
-
-proc objectHeaderToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  result = g.nominalType(ObjectTy, mangle(c, t))
-
-proc tupleToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  var fieldTypes = newSeq[TypeId](t.len)
-  for i in 0..<t.len:
-    fieldTypes[i] = typeToIr(c, g, t[i])
-  let obj = openType(g, ObjectDecl)
-  g.addName mangle(c, t)
-  g.addSize c.conf.getSize(t)
-  g.addAlign c.conf.getAlign(t)
-
-  var accum = OffsetAccum(maxAlign: 1)
-  for i in 0..<t.len:
-    let child = t[i]
-    g.addField "f_" & $i, fieldTypes[i], accum.offset
-
-    computeSizeAlign(c.conf, child)
-    accum.align(child.align)
-    accum.inc(int32(child.size))
-  result = finishType(g, obj)
-
-proc procToIr(c: var TypesCon; g: var TypeGraph; t: PType; addEnv = false): TypeId =
-  var fieldTypes = newSeq[TypeId](0)
-  for i in 0..<t.len:
-    if t[i] == nil or not isCompileTimeOnly(t[i]):
-      fieldTypes.add typeToIr(c, g, t[i])
-  let obj = openType(g, ProcTy)
-
-  case t.callConv
-  of ccNimCall, ccFastCall, ccClosure: g.addAnnotation "__fastcall"
-  of ccStdCall: g.addAnnotation "__stdcall"
-  of ccCDecl: g.addAnnotation "__cdecl"
-  of ccSafeCall: g.addAnnotation "__safecall"
-  of ccSysCall: g.addAnnotation "__syscall"
-  of ccInline: g.addAnnotation "__inline"
-  of ccNoInline: g.addAnnotation "__noinline"
-  of ccThisCall: g.addAnnotation "__thiscall"
-  of ccNoConvention, ccMember: g.addAnnotation ""
-
-  for i in 0..<fieldTypes.len:
-    g.addType fieldTypes[i]
-
-  if addEnv:
-    let a = openType(g, APtrTy)
-    g.addBuiltinType(VoidId)
-    sealType(g, a)
-
-  if tfVarargs in t.flags:
-    g.addVarargs()
-  result = finishType(g, obj)
-
-proc nativeInt(c: TypesCon): TypeId =
-  case c.conf.target.intSize
-  of 2: result = Int16Id
-  of 4: result = Int32Id
-  else: result = Int64Id
-
-proc openArrayPayloadType*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  let e = elementType(t)
-  let elementType = typeToIr(c, g, e)
-  let arr = g.openType AArrayPtrTy
-  g.addType elementType
-  result = finishType(g, arr) # LastArrayTy
-
-proc openArrayToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  # object (a: ArrayPtr[T], len: int)
-  let e = elementType(t)
-  let mangledBase = mangle(c, e)
-  let typeName = "NimOpenArray" & mangledBase
-
-  let elementType = typeToIr(c, g, e)
-  #assert elementType.int >= 0, typeToString(t)
-
-  let p = openType(g, ObjectDecl)
-  g.addName typeName
-  g.addSize c.conf.target.ptrSize*2
-  g.addAlign c.conf.target.ptrSize
-
-  let f = g.openType FieldDecl
-  let arr = g.openType AArrayPtrTy
-  g.addType elementType
-  sealType(g, arr) # LastArrayTy
-  g.addOffset 0
-  g.addName "data"
-  sealType(g, f) # FieldDecl
-
-  g.addField "len", c.nativeInt, c.conf.target.ptrSize
-
-  result = finishType(g, p) # ObjectDecl
-
-proc strPayloadType(c: var TypesCon; g: var TypeGraph): (string, TypeId) =
-  result = ("NimStrPayload", TypeId(-1))
-  let p = openType(g, ObjectDecl)
-  g.addName result[0]
-  g.addSize c.conf.target.ptrSize*2
-  g.addAlign c.conf.target.ptrSize
-
-  g.addField "cap", c.nativeInt, 0
-
-  let f = g.openType FieldDecl
-  let arr = g.openType LastArrayTy
-  g.addBuiltinType Char8Id
-  result[1] = finishType(g, arr) # LastArrayTy
-  g.addOffset c.conf.target.ptrSize # comes after the len field
-  g.addName "data"
-  sealType(g, f) # FieldDecl
-
-  sealType(g, p)
-
-proc strPayloadPtrType*(c: var TypesCon; g: var TypeGraph): (TypeId, TypeId) =
-  let (mangled, arrayType) = strPayloadType(c, g)
-  let ffp = g.openType APtrTy
-  g.addNominalType ObjectTy, mangled
-  result = (finishType(g, ffp), arrayType) # APtrTy
-
-proc stringToIr(c: var TypesCon; g: var TypeGraph): TypeId =
-  #[
-
-    NimStrPayload = object
-      cap: int
-      data: UncheckedArray[char]
-
-    NimStringV2 = object
-      len: int
-      p: ptr NimStrPayload
-
-  ]#
-  let payload = strPayloadType(c, g)
-
-  let str = openType(g, ObjectDecl)
-  g.addName "NimStringV2"
-  g.addSize c.conf.target.ptrSize*2
-  g.addAlign c.conf.target.ptrSize
-
-  g.addField "len", c.nativeInt, 0
-
-  let fp = g.openType FieldDecl
-  let ffp = g.openType APtrTy
-  g.addNominalType ObjectTy, "NimStrPayload"
-  sealType(g, ffp) # APtrTy
-  g.addOffset c.conf.target.ptrSize # comes after 'len' field
-  g.addName "p"
-  sealType(g, fp) # FieldDecl
-
-  result = finishType(g, str) # ObjectDecl
-
-proc seqPayloadType(c: var TypesCon; g: var TypeGraph; t: PType): (string, TypeId) =
-  #[
-    NimSeqPayload[T] = object
-      cap: int
-      data: UncheckedArray[T]
-  ]#
-  let e = elementType(t)
-  result = (mangle(c, e), TypeId(-1))
-  let payloadName = "NimSeqPayload" & result[0]
-
-  let elementType = typeToIr(c, g, e)
-
-  let p = openType(g, ObjectDecl)
-  g.addName payloadName
-  g.addSize c.conf.target.intSize
-  g.addAlign c.conf.target.intSize
-
-  g.addField "cap", c.nativeInt, 0
-
-  let f = g.openType FieldDecl
-  let arr = g.openType LastArrayTy
-  g.addType elementType
-  # DO NOT USE `finishType` here as it is an inner type. This is subtle and we
-  # probably need an even better API here.
-  sealType(g, arr)
-  result[1] = TypeId(arr)
-
-  g.addOffset c.conf.target.ptrSize
-  g.addName "data"
-  sealType(g, f) # FieldDecl
-
-  sealType(g, p)
-
-proc seqPayloadPtrType*(c: var TypesCon; g: var TypeGraph; t: PType): (TypeId, TypeId) =
-  let (mangledBase, arrayType) = seqPayloadType(c, g, t)
-  let ffp = g.openType APtrTy
-  g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
-  result = (finishType(g, ffp), arrayType) # APtrTy
-
-proc seqToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  #[
-    NimSeqV2*[T] = object
-      len: int
-      p: ptr NimSeqPayload[T]
-  ]#
-  let (mangledBase, _) = seqPayloadType(c, g, t)
-
-  let sq = openType(g, ObjectDecl)
-  g.addName "NimSeqV2" & mangledBase
-  g.addSize c.conf.getSize(t)
-  g.addAlign c.conf.getAlign(t)
-
-  g.addField "len", c.nativeInt, 0
-
-  let fp = g.openType FieldDecl
-  let ffp = g.openType APtrTy
-  g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
-  sealType(g, ffp) # APtrTy
-  g.addOffset c.conf.target.ptrSize
-  g.addName "p"
-  sealType(g, fp) # FieldDecl
-
-  result = finishType(g, sq) # ObjectDecl
-
-
-proc closureToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  # struct {fn(args, void* env), env}
-  # typedef struct {$n" &
-  #        "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
-  #        "void* ClE_0;$n} $1;$n"
-  let mangledBase = mangle(c, t)
-  let typeName = "NimClosure" & mangledBase
-
-  let procType = procToIr(c, g, t, addEnv=true)
-
-  let p = openType(g, ObjectDecl)
-  g.addName typeName
-  g.addSize c.conf.getSize(t)
-  g.addAlign c.conf.getAlign(t)
-
-  let f = g.openType FieldDecl
-  g.addType procType
-  g.addOffset 0
-  g.addName "ClP_0"
-  sealType(g, f) # FieldDecl
-
-  let f2 = g.openType FieldDecl
-  let voidPtr = openType(g, APtrTy)
-  g.addBuiltinType(VoidId)
-  sealType(g, voidPtr)
-
-  g.addOffset c.conf.target.ptrSize
-  g.addName "ClE_0"
-  sealType(g, f2) # FieldDecl
-
-  result = finishType(g, p) # ObjectDecl
-
-proc bitsetBasetype*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  let s = int(getSize(c.conf, t))
-  case s
-  of 1: result = UInt8Id
-  of 2: result = UInt16Id
-  of 4: result = UInt32Id
-  of 8: result = UInt64Id
-  else: result = UInt8Id
-
-proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId =
-  if t == nil: return VoidId
-  case t.kind
-  of tyInt:
-    case int(getSize(c.conf, t))
-    of 2: result = Int16Id
-    of 4: result = Int32Id
-    else: result = Int64Id
-  of tyInt8: result = Int8Id
-  of tyInt16: result = Int16Id
-  of tyInt32: result = Int32Id
-  of tyInt64: result = Int64Id
-  of tyFloat:
-    case int(getSize(c.conf, t))
-    of 4: result = Float32Id
-    else: result = Float64Id
-  of tyFloat32: result = Float32Id
-  of tyFloat64: result = Float64Id
-  of tyFloat128: result = getFloat128Type(g)
-  of tyUInt:
-    case int(getSize(c.conf, t))
-    of 2: result = UInt16Id
-    of 4: result = UInt32Id
-    else: result = UInt64Id
-  of tyUInt8: result = UInt8Id
-  of tyUInt16: result = UInt16Id
-  of tyUInt32: result = UInt32Id
-  of tyUInt64: result = UInt64Id
-  of tyBool: result = Bool8Id
-  of tyChar: result = Char8Id
-  of tyVoid: result = VoidId
-  of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange:
-    result = typeToIr(c, g, t.skipModifier)
-  of tyEnum:
-    if firstOrd(c.conf, t) < 0:
-      result = Int32Id
-    else:
-      case int(getSize(c.conf, t))
-      of 1: result = UInt8Id
-      of 2: result = UInt16Id
-      of 4: result = Int32Id
-      of 8: result = Int64Id
-      else: result = Int32Id
-  of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
-    if t.len > 0:
-      result = typeToIr(c, g, t.skipModifier)
-    else:
-      result = TypeId(-1)
-  of tyFromExpr:
-    if t.n != nil and t.n.typ != nil:
-      result = typeToIr(c, g, t.n.typ)
-    else:
-      result = TypeId(-1)
-  of tyArray:
-    cached(c, t):
-      var n = toInt64(lengthOrd(c.conf, t))
-      if n <= 0: n = 1   # make an array of at least one element
-      let elemType = typeToIr(c, g, t.elementType)
-      let a = openType(g, ArrayTy)
-      g.addType(elemType)
-      g.addArrayLen n
-      g.addName mangle(c, t)
-      result = finishType(g, a)
-  of tyPtr, tyRef:
-    cached(c, t):
-      let e = t.elementType
-      if e.kind == tyUncheckedArray:
-        let elemType = typeToIr(c, g, e.elementType)
-        let a = openType(g, AArrayPtrTy)
-        g.addType(elemType)
-        result = finishType(g, a)
-      else:
-        let elemType = typeToIr(c, g, t.elementType)
-        let a = openType(g, APtrTy)
-        g.addType(elemType)
-        result = finishType(g, a)
-  of tyVar, tyLent:
-    cached(c, t):
-      let e = t.elementType
-      if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
-        # skip the modifier, `var openArray` is a (ptr, len) pair too:
-        result = typeToIr(c, g, e)
-      else:
-        let elemType = typeToIr(c, g, e)
-        let a = openType(g, APtrTy)
-        g.addType(elemType)
-        result = finishType(g, a)
-  of tySet:
-    let s = int(getSize(c.conf, t))
-    case s
-    of 1: result = UInt8Id
-    of 2: result = UInt16Id
-    of 4: result = UInt32Id
-    of 8: result = UInt64Id
-    else:
-      # array[U8, s]
-      cached(c, t):
-        let a = openType(g, ArrayTy)
-        g.addType(UInt8Id)
-        g.addArrayLen s
-        g.addName mangle(c, t)
-        result = finishType(g, a)
-  of tyPointer, tyNil:
-    # tyNil can happen for code like: `const CRAP = nil` which we have in posix.nim
-    let a = openType(g, APtrTy)
-    g.addBuiltinType(VoidId)
-    result = finishType(g, a)
-  of tyObject:
-    # Objects are special as they can be recursive in Nim. This is easily solvable.
-    # We check if we are already "processing" t. If so, we produce `ObjectTy`
-    # instead of `ObjectDecl`.
-    cached(c, t):
-      if not c.recursionCheck.containsOrIncl(t.itemId):
-        result = objectToIr(c, g, t)
-      else:
-        result = objectHeaderToIr(c, g, t)
-  of tyTuple:
-    cachedByName(c, t):
-      result = tupleToIr(c, g, t)
-  of tyProc:
-    cached(c, t):
-      if t.callConv == ccClosure:
-        result = closureToIr(c, g, t)
-      else:
-        result = procToIr(c, g, t)
-  of tyVarargs, tyOpenArray:
-    cached(c, t):
-      result = openArrayToIr(c, g, t)
-  of tyString:
-    if c.stringType.int < 0:
-      result = stringToIr(c, g)
-      c.stringType = result
-    else:
-      result = c.stringType
-  of tySequence:
-    cachedByName(c, t):
-      result = seqToIr(c, g, t)
-  of tyCstring:
-    cached(c, t):
-      let a = openType(g, AArrayPtrTy)
-      g.addBuiltinType Char8Id
-      result = finishType(g, a)
-  of tyUncheckedArray:
-    # We already handled the `ptr UncheckedArray` in a special way.
-    cached(c, t):
-      let elemType = typeToIr(c, g, t.elementType)
-      let a = openType(g, LastArrayTy)
-      g.addType(elemType)
-      result = finishType(g, a)
-  of tyUntyped, tyTyped:
-    # this avoids a special case for system.echo which is not a generic but
-    # uses `varargs[typed]`:
-    result = VoidId
-  of tyNone, tyEmpty, tyTypeDesc,
-     tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
-     tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
-     tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
-    result = TypeId(-1)
diff --git a/compiler/nodekinds.nim b/compiler/nodekinds.nim
index 98ae9405d..ccdbbd26d 100644
--- a/compiler/nodekinds.nim
+++ b/compiler/nodekinds.nim
@@ -204,6 +204,7 @@ type
     nkModuleRef           # for .rod file support: A (moduleId, itemId) pair
     nkReplayAction        # for .rod file support: A replay action
     nkNilRodNode          # for .rod file support: a 'nil' PNode
+    nkOpenSym             # container for captured sym that can be overriden by local symbols
 
 const
   nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
diff --git a/compiler/options.nim b/compiler/options.nim
index 356aa6cc8..b77bdd2a3 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -139,7 +139,6 @@ type
     backendCpp = "cpp"
     backendJs = "js"
     backendObjc = "objc"
-    backendNir = "nir"
     # backendNimscript = "nimscript" # this could actually work
     # backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM
 
@@ -147,7 +146,6 @@ type
     cmdNone # not yet processed command
     cmdUnknown # command unmapped
     cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS,
-    cmdCompileToNir,
     cmdCrun # compile and run in nimache
     cmdTcc # run the project via TCC backend
     cmdCheck # semantic checking for whole project
@@ -176,12 +174,11 @@ type
 
 const
   cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
-                  cmdCompileToJS, cmdCrun, cmdCompileToNir}
+                  cmdCompileToJS, cmdCrun}
   cmdDocLike* = {cmdDoc0, cmdDoc, cmdDoc2tex, cmdJsondoc0, cmdJsondoc,
                  cmdCtags, cmdBuildindex}
 
 type
-  NimVer* = tuple[major: int, minor: int, patch: int]
   TStringSeq* = seq[string]
   TGCMode* = enum             # the selected GC
     gcUnselected = "unselected"
@@ -228,7 +225,9 @@ type
     strictDefs,
     strictCaseObjects,
     inferGenericTypes,
-    genericsOpenSym,
+    openSym, # remove nfDisabledOpenSym when this is default
+    # alternative to above:
+    genericsOpenSym
     vtables
 
   LegacyFeature* = enum
@@ -246,13 +245,15 @@ type
     emitGenerics
       ## generics are emitted in the module that contains them.
       ## Useful for libraries that rely on local passC
+    jsNoLambdaLifting
+      ## Old transformation for closures in JS backend
 
   SymbolFilesOption* = enum
     disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
 
   TSystemCC* = enum
     ccNone, ccGcc, ccNintendoSwitch, ccLLVM_Gcc, ccCLang, ccBcc, ccVcc,
-    ccTcc, ccEnv, ccIcl, ccIcc, ccClangCl
+    ccTcc, ccEnv, ccIcl, ccIcc, ccClangCl, ccHipcc, ccNvcc
 
   ExceptionSystem* = enum
     excNone,   # no exception system selected yet
@@ -368,7 +369,6 @@ type
     arguments*: string ## the arguments to be passed to the program that
                        ## should be run
     ideCmd*: IdeCmd
-    oldNewlines*: bool
     cCompiler*: TSystemCC # the used compiler
     modifiedyNotes*: TNoteKinds # notes that have been set/unset from either cmdline/configs
     cmdlineNotes*: TNoteKinds # notes that have been set/unset from cmdline
@@ -395,8 +395,7 @@ type
     outDir*: AbsoluteDir
     jsonBuildFile*: AbsoluteFile
     prefixDir*, libpath*, nimcacheDir*: AbsoluteDir
-    nimStdlibVersion*: NimVer
-    dllOverrides, moduleOverrides*, cfileSpecificOptions*: StringTableRef
+    dllOverrides*, moduleOverrides*, cfileSpecificOptions*: StringTableRef
     projectName*: string # holds a name like 'nim'
     projectPath*: AbsoluteDir # holds a path like /home/alice/projects/nim/compiler/
     projectFull*: AbsoluteFile # projectPath/projectName
@@ -408,7 +407,6 @@ type
     commandArgs*: seq[string] # any arguments after the main command
     commandLine*: string
     extraCmds*: seq[string] # for writeJsonBuildInstructions
-    keepComments*: bool # whether the parser needs to keep comments
     implicitImports*: seq[string] # modules that are to be implicitly imported
     implicitIncludes*: seq[string] # modules that are to be implicitly included
     docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \
@@ -449,16 +447,6 @@ type
     clientProcessId*: int
 
 
-proc parseNimVersion*(a: string): NimVer =
-  # could be moved somewhere reusable
-  result = default(NimVer)
-  if a.len > 0:
-    let b = a.split(".")
-    assert b.len == 3, a
-    template fn(i) = result[i] = b[i].parseInt # could be optimized if needed
-    fn(0)
-    fn(1)
-    fn(2)
 
 proc assignIfDefault*[T](result: var T, val: T, def = default(T)) =
   ## if `result` was already assigned to a value (that wasn't `def`), this is a noop.
@@ -592,7 +580,6 @@ proc newConfigRef*(): ConfigRef =
     command: "", # the main command (e.g. cc, check, scan, etc)
     commandArgs: @[], # any arguments after the main command
     commandLine: "",
-    keepComments: true, # whether the parser needs to keep comments
     implicitImports: @[], # modules that are to be implicitly imported
     implicitIncludes: @[], # modules that are to be implicitly included
     docSeeSrcUrl: "",
@@ -633,12 +620,6 @@ proc newPartialConfigRef*(): ConfigRef =
 proc cppDefine*(c: ConfigRef; define: string) =
   c.cppDefines.incl define
 
-proc getStdlibVersion*(conf: ConfigRef): NimVer =
-  if conf.nimStdlibVersion == (0,0,0):
-    let s = conf.symbols.getOrDefault("nimVersion", "")
-    conf.nimStdlibVersion = s.parseNimVersion
-  result = conf.nimStdlibVersion
-
 proc isDefined*(conf: ConfigRef; symbol: string): bool =
   if conf.symbols.hasKey(symbol):
     result = true
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index 84c2980c4..e8ec22fe1 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -266,7 +266,7 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
     if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in
         {tyOpenArray, tyTuple, tyObject}:
       result = isAssignable(owner, n[1])
-    elif compareTypes(n.typ, n[1].typ, dcEqIgnoreDistinct):
+    elif compareTypes(n.typ, n[1].typ, dcEqIgnoreDistinct, {IgnoreRangeShallow}):
       # types that are equal modulo distinction preserve l-value:
       result = isAssignable(owner, n[1])
   of nkHiddenDeref:
@@ -283,8 +283,15 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
   of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
     result = isAssignable(owner, n[0])
   of nkCallKinds:
-    # builtin slice keeps lvalue-ness:
-    if getMagic(n) in {mArrGet, mSlice}:
+    let m = getMagic(n)
+    if m == mSlice:
+      # builtin slice keeps l-value-ness
+      # except for pointers because slice dereferences
+      if n[1].typ.kind == tyPtr:
+        result = arLValue
+      else:
+        result = isAssignable(owner, n[1])
+    elif m == mArrGet:
       result = isAssignable(owner, n[1])
     elif n.typ != nil:
       case n.typ.kind
diff --git a/compiler/parser.nim b/compiler/parser.nim
index eb7b8c289..747505097 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -1401,7 +1401,7 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode =
     result = primarySuffix(p, result, baseInd, mode)
 
 proc binaryNot(p: var Parser; a: PNode): PNode =
-  if p.tok.tokType == tkNot:
+  if p.tok.tokType == tkNot and p.tok.indent < 0:
     let notOpr = newIdentNodeP(p.tok.ident, p)
     getTok(p)
     optInd(p, notOpr)
diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim
index a44edbb7f..55e7fe892 100644
--- a/compiler/pipelines.nim
+++ b/compiler/pipelines.nim
@@ -13,7 +13,6 @@ when not defined(leanCompiler):
 import std/[syncio, objectdollar, assertions, tables, strutils, strtabs]
 import renderer
 import ic/replayer
-import nir/nir
 
 proc setPipeLinePass*(graph: ModuleGraph; pass: PipelinePass) =
   graph.pipelinePass = pass
@@ -45,10 +44,6 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext):
       result = nil
   of EvalPass, InterpreterPass:
     result = interpreterCode(bModule, semNode)
-  of NirReplPass:
-    result = runCode(bModule, semNode)
-  of NirPass:
-    result = nirBackend(bModule, semNode)
   of NonePass:
     raiseAssert "use setPipeLinePass to set a proper PipelinePass"
 
@@ -111,8 +106,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
     case graph.pipelinePass
     of CgenPass:
       setupCgen(graph, module, idgen)
-    of NirPass:
-      openNirBackend(graph, module, idgen)
     of JSgenPass:
       when not defined(leanCompiler):
         setupJSgen(graph, module, idgen)
@@ -120,8 +113,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
         nil
     of EvalPass, InterpreterPass:
       setupEvalGen(graph, module, idgen)
-    of NirReplPass:
-      setupNirReplGen(graph, module, idgen)
     of GenDependPass:
       setupDependPass(graph, module, idgen)
     of Docgen2Pass:
@@ -209,10 +200,6 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
       discard finalJSCodeGen(graph, bModule, finalNode)
   of EvalPass, InterpreterPass:
     discard interpreterCode(bModule, finalNode)
-  of NirReplPass:
-    discard runCode(bModule, finalNode)
-  of NirPass:
-    closeNirBackend(bModule, finalNode)
   of SemPass, GenDependPass:
     discard
   of Docgen2Pass, Docgen2TexPass:
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index a644639fe..9a298cd90 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -81,14 +81,14 @@ const
     wRequiresInit, wNoalias, wAlign, wNoInit} - {wExportNims, wNodecl} # why exclude these?
   varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
     wMagic, wHeader, wCompilerProc, wCore, wDynlib,
-    wNoInit, wCompileTime, wGlobal,
+    wNoInit, wCompileTime, wGlobal, wLiftLocals,
     wGensym, wInject, wCodegenDecl,
     wGuard, wGoto, wCursor, wNoalias, wAlign}
   constPragmas* = declPragmas + {wHeader, wMagic,
     wGensym, wInject,
     wIntDefine, wStrDefine, wBoolDefine, wDefine,
     wCompilerProc, wCore}
-  paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy, wCodegenDecl}
+  paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy, wCodegenDecl, wExportc, wExportCpp}
   letPragmas* = varPragmas
   procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect,
                       wThread, wRaises, wEffectsOf, wLocks, wTags, wForbids, wGcSafe,
@@ -156,16 +156,16 @@ proc pragmaEnsures(c: PContext, n: PNode) =
 proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) =
   # special cases to improve performance:
   if extname == "$1":
-    s.loc.r = rope(s.name.s)
+    s.loc.snippet = rope(s.name.s)
   elif '$' notin extname:
-    s.loc.r = rope(extname)
+    s.loc.snippet = rope(extname)
   else:
     try:
-      s.loc.r = rope(extname % s.name.s)
+      s.loc.snippet = rope(extname % s.name.s)
     except ValueError:
       localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
   when hasFFI:
-    s.cname = $s.loc.r
+    s.cname = $s.loc.snippet
 
 
 proc makeExternImport(c: PContext; s: PSym, extname: string, info: TLineInfo) =
@@ -370,7 +370,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
 proc processNote(c: PContext, n: PNode) =
   template handleNote(enumVals, notes) =
     let x = findStr(enumVals.a, enumVals.b, n[0][1].ident.s, errUnknown)
-    if x !=  errUnknown:
+    if x != errUnknown:
       nk = TNoteKind(x)
       let x = c.semConstBoolExpr(c, n[1])
       n[1] = x
@@ -480,6 +480,18 @@ proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
     # calling conventions (boring...):
     localError(c.config, n.info, "option expected")
 
+proc checkPushedPragma(c: PContext, n: PNode) =
+  let keyDeep = n.kind in nkPragmaCallKinds and n.len > 1
+  var key = if keyDeep: n[0] else: n
+  if key.kind in nkIdentKinds:
+    let ident = considerQuotedIdent(c, key)
+    var userPragma = strTableGet(c.userPragmas, ident)
+    if userPragma == nil:
+      let k = whichKeyword(ident)
+      # TODO: might as well make a list which is not accepted by `push`: emit, cast etc.
+      if k == wEmit:
+        localError(c.config, n.info, "an 'emit' pragma cannot be pushed")
+
 proc processPush(c: PContext, n: PNode, start: int) =
   if n[start-1].kind in nkPragmaCallKinds:
     localError(c.config, n.info, "'push' cannot have arguments")
@@ -487,6 +499,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
   for i in start..<n.len:
     if not tryProcessOption(c, n[i], c.config.options):
       # simply store it somewhere:
+      checkPushedPragma(c, n[i])
       if x.otherPragmas.isNil:
         x.otherPragmas = newNodeI(nkPragma, n.info)
       x.otherPragmas.add n[i]
@@ -787,13 +800,14 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
 proc semCustomPragma(c: PContext, n: PNode, sym: PSym): PNode =
   var callNode: PNode
 
-  if n.kind in {nkIdent, nkSym}:
+  case n.kind
+  of nkIdentKinds:
     # pragma -> pragma()
     callNode = newTree(nkCall, n)
-  elif n.kind == nkExprColonExpr:
+  of nkExprColonExpr:
     # pragma: arg -> pragma(arg)
     callNode = newTree(nkCall, n[0], n[1])
-  elif n.kind in nkPragmaCallKinds:
+  of nkPragmaCallKinds - {nkExprColonExpr}:
     callNode = n
   else:
     invalidPragma(c, n)
@@ -869,6 +883,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
 
     # number of pragmas increase/decrease with user pragma expansion
     inc c.instCounter
+    defer: dec c.instCounter
     if c.instCounter > 100:
       globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s)
 
@@ -878,7 +893,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
     pragma(c, sym, userPragma.ast, validPragmas, isStatement)
     n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
     i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
-    dec c.instCounter
   else:
     let k = whichKeyword(ident)
     if k in validPragmas:
@@ -1001,7 +1015,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         incl(sym.loc.flags, lfHeader)
         incl(sym.loc.flags, lfNoDecl)
         # implies nodecl, because otherwise header would not make sense
-        if sym.loc.r == "": sym.loc.r = rope(sym.name.s)
+        if sym.loc.snippet == "": sym.loc.snippet = rope(sym.name.s)
       of wNoSideEffect:
         noVal(c, it)
         if sym != nil:
@@ -1295,7 +1309,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         noVal(c, it)
         if sym == nil: invalidPragma(c, it)
         else: sym.flags.incl sfUsed
-      of wLiftLocals: discard
+      of wLiftLocals:
+        sym.flags.incl(sfForceLift)
       of wRequires, wInvariant, wAssume, wAssert:
         pragmaProposition(c, it)
       of wEnsures:
@@ -1329,6 +1344,16 @@ proc mergePragmas(n, pragmas: PNode) =
   else:
     for p in pragmas: n[pragmasPos].add p
 
+proc mergeValidPragmas(n, pragmas: PNode, validPragmas: TSpecialWords) =
+  if n[pragmasPos].kind == nkEmpty:
+    n[pragmasPos] = newNodeI(nkPragma, n.info)
+  for p in pragmas:
+    let prag = whichPragma(p)
+    if prag in validPragmas:
+      let copy = copyTree(p)
+      overwriteLineInfo copy, n.info
+      n[pragmasPos].add copy
+
 proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
                       validPragmas: TSpecialWords) =
   if sym != nil and sym.kind != skModule:
@@ -1342,7 +1367,8 @@ proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
             internalError(c.config, info, "implicitPragmas")
           inc i
         popInfoContext(c.config)
-        if sym.kind in routineKinds and sym.ast != nil: mergePragmas(sym.ast, o)
+        if sym.kind in routineKinds and sym.ast != nil:
+          mergeValidPragmas(sym.ast, o, validPragmas)
 
     if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
       localError(c.config, info, ".dynlib requires .exportc")
@@ -1351,7 +1377,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
         sfImportc in sym.flags and lib != nil:
       incl(sym.loc.flags, lfDynamicLib)
       addToLib(lib, sym)
-      if sym.loc.r == "": sym.loc.r = rope(sym.name.s)
+      if sym.loc.snippet == "": sym.loc.snippet = rope(sym.name.s)
 
 proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
   if n == nil: return false
diff --git a/compiler/pushpoppragmas.nim b/compiler/pushpoppragmas.nim
new file mode 100644
index 000000000..773e7013b
--- /dev/null
+++ b/compiler/pushpoppragmas.nim
@@ -0,0 +1,54 @@
+import pragmas, options, ast, trees, lineinfos, idents, wordrecg
+import std/assertions
+
+import renderer
+
+
+proc processNote(config: ConfigRef, n: PNode) =
+  template handleNote(enumVals, notes) =
+    let x = findStr(enumVals.a, enumVals.b, n[0][1].ident.s, errUnknown)
+    assert x != errUnknown
+    assert n[1].kind == nkIntLit
+
+    nk = TNoteKind(x)
+    if n[1].intVal != 0: incl(notes, nk)
+    else: excl(notes, nk)
+
+  var nk: TNoteKind
+  case whichKeyword(n[0][0].ident)
+  of wHint: handleNote(hintMin .. hintMax, config.notes)
+  of wWarning: handleNote(warnMin .. warnMax, config.notes)
+  of wWarningAsError: handleNote(warnMin .. warnMax, config.warningAsErrors)
+  of wHintAsError: handleNote(hintMin .. hintMax, config.warningAsErrors)
+  else: discard
+
+proc pushBackendOption(optionsStack: var seq[(TOptions, TNoteKinds)], options: TOptions, notes: TNoteKinds) =
+  optionsStack.add (options, notes)
+
+proc popBackendOption(config: ConfigRef, optionsStack: var seq[(TOptions, TNoteKinds)], options: var TOptions) =
+  let entry = optionsStack[^1]
+  options = entry[0]
+  config.notes = entry[1]
+  optionsStack.setLen(optionsStack.len-1)
+
+proc processPushBackendOption*(config: ConfigRef, optionsStack: var seq[(TOptions, TNoteKinds)], options: var TOptions,
+                           n: PNode, start: int) =
+  pushBackendOption(optionsStack, options, config.notes)
+  for i in start..<n.len:
+    let it = n[i]
+    if it.kind in nkPragmaCallKinds and it.len == 2:
+      if it[0].kind == nkBracketExpr and
+          it[0].len == 2 and
+          it[0][1].kind == nkIdent and it[0][0].kind == nkIdent:
+        processNote(config, it)
+      elif it[1].kind == nkIntLit:
+        let sw = whichPragma(it[0])
+        let opts = pragmaToOptions(sw)
+        if opts != {}:
+          if it[1].intVal != 0:
+            options.incl opts
+          else:
+            options.excl opts
+
+template processPopBackendOption*(config: ConfigRef, optionsStack: var seq[(TOptions, TNoteKinds)], options: var TOptions) =
+  popBackendOption(config, optionsStack, options)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 3a7c60953..cc07c0c2d 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -442,6 +442,11 @@ proc atom(g: TSrcGen; n: PNode): string =
       result = $n.floatVal & "\'f64"
     else:
       result = litAux(g, n, (cast[ptr int64](addr(n.floatVal)))[], 8) & "\'f64"
+  of nkFloat128Lit:
+    if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
+      result = $n.floatVal & "\'f128"
+    else:
+      result = litAux(g, n, (cast[ptr int64](addr(n.floatVal)))[], 8) & "\'f128"
   of nkNilLit: result = "nil"
   of nkType:
     if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
@@ -514,6 +519,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
     result = if n.len > 0: lcomma(g, n) + 2 else: len("{:}")
   of nkClosedSymChoice, nkOpenSymChoice:
     if n.len > 0: result += lsub(g, n[0])
+  of nkOpenSym: result = lsub(g, n[0])
   of nkTupleTy: result = lcomma(g, n) + len("tuple[]")
   of nkTupleClassTy: result = len("tuple")
   of nkDotExpr: result = lsons(g, n) + 1
@@ -1013,7 +1019,7 @@ proc bracketKind*(g: TSrcGen, n: PNode): BracketKind =
 proc skipHiddenNodes(n: PNode): PNode =
   result = n
   while result != nil:
-    if result.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv} and result.len > 1:
+    if result.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv, nkOpenSym} and result.len > 1:
       result = result[1]
     elif result.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString} and
         result.len > 0:
@@ -1275,6 +1281,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
       put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
     else:
       gsub(g, n, 0)
+  of nkOpenSym: gsub(g, n, 0)
   of nkPar, nkClosure:
     put(g, tkParLe, "(")
     gcomma(g, n, c)
diff --git a/compiler/reorder.nim b/compiler/reorder.nim
index 31c8befe2..2f7c04af1 100644
--- a/compiler/reorder.nim
+++ b/compiler/reorder.nim
@@ -322,6 +322,14 @@ proc intersects(s1, s2: IntSet): bool =
     if s2.contains(a):
       return true
 
+proc hasPushOrPopPragma(n: DepN): bool =
+  # Checks if the tree node has some pragmas that do not
+  # play well with reordering, like the push/pop pragma
+  # no crossing for push/pop barrier
+  let a = n.pnode
+  result = a.kind == nkPragma and a[0].kind == nkIdent and
+      (a[0].ident.s == "push" or a[0].ident.s == "pop")
+
 proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
   # Build a dependency graph
   result = newSeqOfCap[DepN](deps.len)
@@ -363,6 +371,13 @@ proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
             for dep in deps[i][0]:
               if dep in declares:
                 ni.expls.add "one declares \"" & idNames[dep] & "\" and the other defines it"
+      elif hasPushOrPopPragma(nj):
+        # Every node that comes after a push/pop pragma must
+        # depend on it; vice versa
+        if j < i:
+          ni.kids.add nj
+        else:
+          nj.kids.add ni
       else:
         for d in declares:
           if uses.contains(d):
@@ -403,18 +418,7 @@ proc getStrongComponents(g: var DepG): seq[seq[DepN]] =
     if v.idx < 0:
       strongConnect(v, idx, s, result)
 
-proc hasForbiddenPragma(n: PNode): bool =
-  # Checks if the tree node has some pragmas that do not
-  # play well with reordering, like the push/pop pragma
-  result = false
-  for a in n:
-    if a.kind == nkPragma and a[0].kind == nkIdent and
-        a[0].ident.s == "push":
-      return true
-
 proc reorder*(graph: ModuleGraph, n: PNode, module: PSym): PNode =
-  if n.hasForbiddenPragma:
-    return n
   var includedFiles = initIntSet()
   let mpath = toFullPath(graph.config, module.fileIdx)
   let n = expandIncludes(graph, module, n, mpath,
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 92c21aece..2cf93d365 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -21,7 +21,7 @@ import
   extccomp
 
 import vtables
-import std/[strtabs, math, tables, intsets, strutils]
+import std/[strtabs, math, tables, intsets, strutils, packedsets]
 
 when not defined(leanCompiler):
   import spawn
@@ -103,7 +103,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
     result = nil
     for ch in arg:
       if sameType(ch.typ, formal):
-        return getConstExpr(c.module, ch, c.idgen, c.graph)
+        return ch
     typeMismatch(c.config, info, formal, arg.typ, arg)
   else:
     result = indexTypesMatch(c, formal, arg.typ, arg)
@@ -222,66 +222,7 @@ proc shouldCheckCaseCovered(caseTyp: PType): bool =
   else:
     discard
 
-proc endsInNoReturn(n: PNode): bool =
-  ## check if expr ends the block like raising or call of noreturn procs do
-  result = false # assume it does return
-
-  template checkBranch(branch) =
-    if not endsInNoReturn(branch):
-      # proved a branch returns
-      return false
-
-  var it = n
-  # skip these beforehand, no special handling needed
-  while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
-    it = it.lastSon
-
-  case it.kind
-  of nkIfStmt:
-    var hasElse = false
-    for branch in it:
-      checkBranch:
-        if branch.len == 2:
-          branch[1]
-        elif branch.len == 1:
-          hasElse = true
-          branch[0]
-        else:
-          raiseAssert "Malformed `if` statement during endsInNoReturn"
-    # none of the branches returned
-    result = hasElse # Only truly a no-return when it's exhaustive
-  of nkCaseStmt:
-    let caseTyp = skipTypes(it[0].typ, abstractVar-{tyTypeDesc})
-    # semCase should already have checked for exhaustiveness in this case
-    # effectively the same as having an else
-    var hasElse = caseTyp.shouldCheckCaseCovered()
-
-    # actual noreturn checks
-    for i in 1 ..< it.len:
-      let branch = it[i]
-      checkBranch:
-        case branch.kind
-        of nkOfBranch:
-          branch[^1]
-        of nkElifBranch:
-          branch[1]
-        of nkElse:
-          hasElse = true
-          branch[0]
-        else:
-          raiseAssert "Malformed `case` statement in endsInNoReturn"
-    # Can only guarantee a noreturn if there is an else or it's exhaustive
-    result = hasElse
-  of nkTryStmt:
-    checkBranch(it[0])
-    for i in 1 ..< it.len:
-      let branch = it[i]
-      checkBranch(branch[^1])
-    # none of the branches returned
-    result = true
-  else:
-    result = it.kind in nkLastBlockStmts or
-      it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
+proc endsInNoReturn(n: PNode): bool
 
 proc commonType*(c: PContext; x: PType, y: PNode): PType =
   # ignore exception raising branches in case/if expressions
@@ -313,6 +254,8 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
     result.owner = getCurrOwner(c)
   else:
     result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
+    if find(result.name.s, '`') >= 0:
+      result.flags.incl sfWasGenSym
   #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
   #  incl(result.flags, sfGlobal)
   when defined(nimsuggest):
@@ -322,7 +265,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
                  allowed: TSymFlags): PSym
   # identifier with visibility
 proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
-                        allowed: TSymFlags): PSym
+                        allowed: TSymFlags, fromTopLevel = false): PSym
 
 proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind;
                       flags: TTypeAllowedFlags = {}) =
@@ -554,7 +497,6 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
 
 const
   errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
-  errFloatToString = "cannot convert '$1' to '$2'"
 
 proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
                   flags: TExprFlags = {}; expectedType: PType = nil): PNode =
@@ -708,7 +650,8 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault:
 
 proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode =
   let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes)
-  if aTypSkip.kind == tyObject:
+  case aTypSkip.kind
+  of tyObject:
     let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, checkDefault)
     if child.len > 0:
       var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp))
@@ -717,7 +660,7 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
       result = semExpr(c, asgnExpr)
     else:
       result = nil
-  elif aTypSkip.kind == tyArray:
+  of tyArray:
     let child = defaultNodeField(c, a, aTypSkip[1], checkDefault)
 
     if child != nil:
@@ -730,7 +673,7 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
       result.typ = aTyp
     else:
       result = nil
-  elif aTypSkip.kind == tyTuple:
+  of tyTuple:
     var hasDefault = false
     if aTypSkip.n != nil:
       let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault, checkDefault)
@@ -743,6 +686,11 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): P
         result = nil
     else:
       result = nil
+  of tyRange:
+    if c.graph.config.isDefined("nimPreviewRangeDefault"):
+      result = firstRange(c.config, aTypSkip)
+    else:
+      result = nil
   else:
     result = nil
 
@@ -779,6 +727,7 @@ proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PCo
   result.semOverloadedCall = semOverloadedCall
   result.semInferredLambda = semInferredLambda
   result.semGenerateInstance = generateInstance
+  result.instantiateOnlyProcType = instantiateOnlyProcType
   result.semTypeNode = semTypeNode
   result.instTypeBoundOp = sigmatch.instTypeBoundOp
   result.hasUnresolvedArgs = hasUnresolvedArgs
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index a136cf4fe..13f2273a9 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -246,7 +246,16 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
       candidates.add(getProcHeader(c.config, err.sym, prefer))
     candidates.addDeclaredLocMaybe(c.config, err.sym)
     candidates.add("\n")
-    let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
+    const genericParamMismatches = {kGenericParamTypeMismatch, kExtraGenericParam, kMissingGenericParam}
+    let isGenericMismatch = err.firstMismatch.kind in genericParamMismatches
+    var argList = n
+    if isGenericMismatch and n[0].kind == nkBracketExpr:
+      argList = n[0]
+    let nArg =
+      if err.firstMismatch.arg < argList.len:
+        argList[err.firstMismatch.arg]
+      else:
+        nil
     let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
     if n.len > 1:
       if verboseTypeMismatch notin c.config.legacyFeatures:
@@ -269,6 +278,12 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
         of kMissingParam:
           candidates.add("  missing parameter: " & nameParam)
           candidates.add "\n"
+        of kExtraGenericParam:
+          candidates.add("  extra generic param given")
+          candidates.add "\n"
+        of kMissingGenericParam:
+          candidates.add("  missing generic parameter: " & nameParam)
+          candidates.add "\n"
         of kVarNeeded:
           doAssert nArg != nil
           doAssert err.firstMismatch.formal != nil
@@ -278,6 +293,8 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
           candidates.add "\n"
         of kTypeMismatch:
           doAssert nArg != nil
+          if nArg.kind in nkSymChoices:
+            candidates.add ambiguousIdentifierMsg(nArg, indent = 2)
           let wanted = err.firstMismatch.formal.typ
           doAssert err.firstMismatch.formal != nil
           doAssert wanted != nil
@@ -292,9 +309,39 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
             candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
             effectProblem(wanted, got, candidates, c)
             candidates.add "\n"
+        of kGenericParamTypeMismatch:
+          let pos = err.firstMismatch.arg
+          doAssert n[0].kind == nkBracketExpr and pos < n[0].len
+          let arg = n[0][pos]
+          doAssert arg != nil
+          var wanted = err.firstMismatch.formal.typ
+          if wanted.kind == tyGenericParam and wanted.genericParamHasConstraints:
+            wanted = wanted.genericConstraint
+          let got = arg.typ.skipTypes({tyTypeDesc})
+          doAssert err.firstMismatch.formal != nil
+          doAssert wanted != nil
+          doAssert got != nil
+          candidates.add "  generic parameter mismatch, expected "
+          candidates.addTypeDeclVerboseMaybe(c.config, wanted)
+          candidates.add " but got '"
+          candidates.add renderTree(arg)
+          candidates.add "' of type: "
+          candidates.addTypeDeclVerboseMaybe(c.config, got)
+          if nArg.kind in nkSymChoices:
+            candidates.add "\n"
+            candidates.add ambiguousIdentifierMsg(nArg, indent = 2)
+          if got != nil and got.kind == tyProc and wanted.kind == tyProc:
+            # These are proc mismatches so,
+            # add the extra explict detail of the mismatch
+            candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
+          if got != nil:
+            effectProblem(wanted, got, candidates, c)
+          candidates.add "\n"
         of kUnknown: discard "do not break 'nim check'"
       else:
         candidates.add("  first type mismatch at position: " & $err.firstMismatch.arg)
+        if err.firstMismatch.kind in genericParamMismatches:
+          candidates.add(" in generic parameters")
         # candidates.add "\n  reason: " & $err.firstMismatch.kind # for debugging
         case err.firstMismatch.kind
         of kUnknownNamedParam:
@@ -306,9 +353,16 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
         of kPositionalAlreadyGiven: candidates.add("\n  positional param was already given as named param")
         of kExtraArg: candidates.add("\n  extra argument given")
         of kMissingParam: candidates.add("\n  missing parameter: " & nameParam)
-        of kTypeMismatch, kVarNeeded:
+        of kExtraGenericParam:
+          candidates.add("\n  extra generic param given")
+        of kMissingGenericParam:
+          candidates.add("\n  missing generic parameter: " & nameParam)
+        of kTypeMismatch, kGenericParamTypeMismatch, kVarNeeded:
           doAssert nArg != nil
-          let wanted = err.firstMismatch.formal.typ
+          var wanted = err.firstMismatch.formal.typ
+          if isGenericMismatch and wanted.kind == tyGenericParam and
+              wanted.genericParamHasConstraints:
+            wanted = wanted.genericConstraint
           doAssert err.firstMismatch.formal != nil
           candidates.add("\n  required type for " & nameParam &  ": ")
           candidates.addTypeDeclVerboseMaybe(c.config, wanted)
@@ -319,8 +373,12 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
           else:
             candidates.add renderTree(nArg)
             candidates.add "' is of type: "
-            let got = nArg.typ
+            var got = nArg.typ
+            if isGenericMismatch: got = got.skipTypes({tyTypeDesc})
             candidates.addTypeDeclVerboseMaybe(c.config, got)
+            if nArg.kind in nkSymChoices:
+              candidates.add "\n"
+              candidates.add ambiguousIdentifierMsg(nArg, indent = 2)
             doAssert wanted != nil
             if got != nil:
               if got.kind == tyProc and wanted.kind == tyProc:
@@ -331,8 +389,8 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
 
         of kUnknown: discard "do not break 'nim check'"
         candidates.add "\n"
-      if err.firstMismatch.arg == 1 and nArg.kind == nkTupleConstr and
-          n.kind == nkCommand:
+      if err.firstMismatch.arg == 1 and nArg != nil and
+          nArg.kind == nkTupleConstr and n.kind == nkCommand:
         maybeWrongSpace = true
     for diag in err.diagnostics:
       candidates.add(diag & "\n")
@@ -409,23 +467,6 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
       result.add("\n" & errExpectedPosition & "\n" & candidates)
     localError(c.config, n.info, result)
 
-proc bracketNotFoundError(c: PContext; n: PNode) =
-  var errors: CandidateErrors = @[]
-  var o: TOverloadIter = default(TOverloadIter)
-  let headSymbol = n[0]
-  var symx = initOverloadIter(o, c, headSymbol)
-  while symx != nil:
-    if symx.kind in routineKinds:
-      errors.add(CandidateError(sym: symx,
-                                firstMismatch: MismatchInfo(),
-                                diagnostics: @[],
-                                enabled: false))
-    symx = nextOverloadIter(o, c, headSymbol)
-  if errors.len == 0:
-    localError(c.config, n.info, "could not resolve: " & $n)
-  else:
-    notFoundError(c, n, errors)
-
 proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
   result = ""
   if c.compilesContextId > 0:
@@ -518,7 +559,8 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
     if overloadsState == csEmpty and result.state == csEmpty:
       if efNoUndeclared notin flags: # for tests/pragmas/tcustom_pragma.nim
         result.state = csNoMatch
-        if efNoDiagnostics in flags:
+        if c.inGenericContext > 0 and nfExprCall in n.flags:
+          # untyped expression calls end up here, see #24099
           return
         # xxx adapt/use errorUndeclaredIdentifierHint(c, n, f.ident)
         localError(c.config, n.info, getMsgDiagnostic(c, flags, n, f))
@@ -554,6 +596,39 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         getProcHeader(c.config, alt.calleeSym),
         args])
 
+proc bracketNotFoundError(c: PContext; n: PNode; flags: TExprFlags) =
+  var errors: CandidateErrors = @[]
+  let headSymbol = n[0]
+  block:
+    # we build a closed symchoice of all `[]` overloads for their errors,
+    # except add a custom error for the magics which always match
+    var choice = newNodeIT(nkClosedSymChoice, headSymbol.info, newTypeS(tyNone, c))
+    var o: TOverloadIter = default(TOverloadIter)
+    var symx = initOverloadIter(o, c, headSymbol)
+    while symx != nil:
+      if symx.kind in routineKinds:
+        if symx.magic in {mArrGet, mArrPut}:
+          errors.add(CandidateError(sym: symx,
+                                    firstMismatch: MismatchInfo(),
+                                    diagnostics: @[],
+                                    enabled: false))
+        else:
+          choice.add newSymNode(symx, headSymbol.info)
+      symx = nextOverloadIter(o, c, headSymbol)
+    n[0] = choice
+  # copied from semOverloadedCallAnalyzeEffects, might be overkill:
+  const baseFilter = {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}
+  let filter =
+    if flags*{efInTypeof, efWantIterator, efWantIterable} != {}:
+      baseFilter + {skIterator}
+    else: baseFilter
+  # this will add the errors:
+  var r = resolveOverloads(c, n, n, filter, flags, errors, true)
+  if errors.len == 0:
+    localError(c.config, n.info, "could not resolve: " & $n)
+  else:
+    notFoundError(c, n, errors)
+
 proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
   let a = if a.kind == nkHiddenDeref: a[0] else: a
   if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
@@ -595,7 +670,7 @@ proc inferWithMetatype(c: PContext, formal: PType,
     result = copyTree(arg)
     result.typ = formal
 
-proc updateDefaultParams(call: PNode) =
+proc updateDefaultParams(c: PContext, call: PNode) =
   # In generic procs, the default parameter may be unique for each
   # instantiation (see tlateboundgenericparams).
   # After a call is resolved, we need to re-assign any default value
@@ -605,8 +680,18 @@ proc updateDefaultParams(call: PNode) =
   let calleeParams = call[0].sym.typ.n
   for i in 1..<call.len:
     if nfDefaultParam in call[i].flags:
-      let def = calleeParams[i].sym.ast
+      let formal = calleeParams[i].sym
+      let def = formal.ast
       if nfDefaultRefsParam in def.flags: call.flags.incl nfDefaultRefsParam
+      # mirrored with sigmatch:
+      if def.kind == nkEmpty:
+        # The default param value is set to empty in `instantiateProcType`
+        # when the type of the default expression doesn't match the type
+        # of the instantiated proc param:
+        pushInfoContext(c.config, call.info, call[0].sym.detailedInfo)
+        typeMismatch(c.config, def.info, formal.typ, def.typ, formal.ast)
+        popInfoContext(c.config)
+        def.typ = errorType(c)
       call[i] = def
 
 proc getCallLineInfo(n: PNode): TLineInfo =
@@ -686,12 +771,12 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
   markUsed(c, info, finalCallee)
   onUse(info, finalCallee)
   assert finalCallee.ast != nil
-  if x.hasFauxMatch:
+  if x.matchedErrorType:
     result = x.call
     result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
-    if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
-      result.typ = newTypeS(x.fauxMatch, c)
-      if result.typ.kind == tyError: incl result.typ.flags, tfCheckedForDestructor
+    if containsGenericType(result.typ):
+      result.typ = newTypeS(tyError, c)
+      incl result.typ.flags, tfCheckedForDestructor
     return
   let gp = finalCallee.ast[genericParamsPos]
   if gp.isGenericParams:
@@ -725,8 +810,9 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
   result = x.call
   instGenericConvertersSons(c, result, x)
   result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
-  result.typ = finalCallee.typ.returnType
-  updateDefaultParams(result)
+  if finalCallee.magic notin {mArrGet, mArrPut}:
+    result.typ = finalCallee.typ.returnType
+  updateDefaultParams(c, result)
 
 proc canDeref(n: PNode): bool {.inline.} =
   result = n.len >= 2 and (let t = n[1].typ;
@@ -751,7 +837,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
               candidates)
     result = semResolvedCall(c, r, n, flags, expectedType)
   else:
-    if efDetermineType in flags and c.inGenericContext > 0 and c.matchedConcept == nil:
+    if c.inGenericContext > 0 and c.matchedConcept == nil:
       result = semGenericStmt(c, n)
       result.typ = makeTypeFromExpr(c, result.copyTree)
     elif efExplain notin flags:
@@ -769,21 +855,16 @@ proc explicitGenericInstError(c: PContext; n: PNode): PNode =
   result = n
 
 proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
+  if s.kind in {skTemplate, skMacro}:
+    internalError c.config, n.info, "cannot get explicitly instantiated symbol of " &
+      (if s.kind == skTemplate: "template" else: "macro")
   # binding has to stay 'nil' for this to work!
   var m = newCandidate(c, s, nil)
-
-  for i in 1..<n.len:
-    let formal = s.ast[genericParamsPos][i-1].typ
-    var arg = n[i].typ
-    # try transforming the argument into a static one before feeding it into
-    # typeRel
-    if formal.kind == tyStatic and arg.kind != tyStatic:
-      let evaluated = c.semTryConstExpr(c, n[i], n[i].typ)
-      if evaluated != nil:
-        arg = newTypeS(tyStatic, c, son = evaluated.typ)
-        arg.n = evaluated
-    let tm = typeRel(m, formal, arg)
-    if tm in {isNone, isConvertible}: return nil
+  matchGenericParams(m, n, s)
+  if m.state != csMatch:
+    # state is csMatch only if *all* generic params were matched,
+    # including implicit parameters
+    return nil
   var newInst = generateInstance(c, s, m.bindings, n.info)
   newInst.typ.flags.excl tfUnresolved
   let info = getCallLineInfo(n)
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 12930feca..ca35ddc53 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -73,9 +73,9 @@ type
     efNoUndeclared, efIsDotCall, efCannotBeDotCall,
       # Use this if undeclared identifiers should not raise an error during
       # overload resolution.
-    efNoDiagnostics,
     efTypeAllowed # typeAllowed will be called after
     efWantNoDefaults
+    efIgnoreDefaults # var statements without initialization
     efAllowSymChoice # symchoice node should not be resolved
 
   TExprFlags* = set[TExprFlag]
@@ -139,6 +139,9 @@ type
     semInferredLambda*: proc(c: PContext, pt: Table[ItemId, PType], n: PNode): PNode
     semGenerateInstance*: proc (c: PContext, fn: PSym, pt: Table[ItemId, PType],
                                 info: TLineInfo): PSym
+    instantiateOnlyProcType*: proc (c: PContext, pt: TypeMapping,
+                                    prc: PSym, info: TLineInfo): PType
+      # used by sigmatch for explicit generic instantiations
     includedFiles*: IntSet    # used to detect recursive include files
     pureEnumFields*: TStrTable   # pure enum fields that can be used unambiguously
     userPragmas*: TStrTable
@@ -168,6 +171,7 @@ type
     inUncheckedAssignSection*: int
     importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id])
     skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance, sets and generic bodies.
+    inTypeofContext*: int
   TBorrowState* = enum
     bsNone, bsReturnNotMatch, bsNoDistinct, bsGeneric, bsNotSupported, bsMatch
 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 17a3082ff..2885142a7 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -138,7 +138,71 @@ proc resolveSymChoice(c: PContext, n: var PNode, flags: TExprFlags = {}, expecte
       # to mirror behavior before overloadable enums
       n = n[0]
 
+proc semOpenSym(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType,
+                warnDisabled = false): PNode =
+  ## sem the child of an `nkOpenSym` node, that is, captured symbols that can be
+  ## replaced by newly injected symbols in generics. `s` must be the captured
+  ## symbol if the original node is an `nkSym` node; and `nil` if it is an
+  ## `nkOpenSymChoice`, in which case only non-overloadable injected symbols
+  ## will be considered.
+  let isSym = n.kind == nkSym
+  let ident = n.getPIdent
+  assert ident != nil
+  let id = newIdentNode(ident, n.info)
+  c.isAmbiguous = false
+  let s2 = qualifiedLookUp(c, id, {})
+  # for `nkSym`, the first found symbol being different and unambiguous is
+  # enough to replace the original
+  # for `nkOpenSymChoice`, the first found symbol must be non-overloadable,
+  # since otherwise we have to use regular `nkOpenSymChoice` functionality
+  # but of the overloadable sym kinds, semExpr does not handle skModule, skMacro, skTemplate
+  # as overloaded in the case where `nkIdent` finds them first
+  if s2 != nil and not c.isAmbiguous and
+      ((isSym and s2 != n.sym) or
+        (not isSym and s2.kind notin OverloadableSyms-{skModule, skMacro, skTemplate})):
+    # only consider symbols defined under current proc:
+    var o = s2.owner
+    while o != nil:
+      if o == c.p.owner:
+        if not warnDisabled:
+          result = semExpr(c, id, flags, expectedType)
+          return
+        else:
+          var msg =
+            "a new symbol '" & ident.s & "' has been injected during " &
+            # msgContext should show what is being instantiated:
+            "template or generic instantiation, however "
+          if isSym:
+            msg.add(
+              getSymRepr(c.config, n.sym) & " captured at " &
+              "the proc declaration will be used instead; " &
+              "either enable --experimental:openSym to use the injected symbol, " &
+              "or `bind` this captured symbol explicitly")
+          else:
+            msg.add(
+              "overloads of " & ident.s & " will be used instead; " &
+              "either enable --experimental:openSym to use the injected symbol, " &
+              "or `bind` this symbol explicitly")
+          message(c.config, n.info, warnIgnoredSymbolInjection, msg)
+          break
+      o = o.owner
+  # nothing found
+  n.flags.excl nfDisabledOpenSym
+  if not warnDisabled and isSym:
+    result = semExpr(c, n, flags, expectedType)
+  else:
+    result = nil
+    if not isSym:
+      # set symchoice node type back to None
+      n.typ = newTypeS(tyNone, c)
+
 proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
+  if n.kind == nkOpenSymChoice:
+    result = semOpenSym(c, n, flags, expectedType,
+      warnDisabled = nfDisabledOpenSym in n.flags and
+        genericsOpenSym notin c.features)
+    if result != nil:
+      return
   result = n
   resolveSymChoice(c, result, flags, expectedType)
   if isSymChoice(result) and result.len == 1:
@@ -218,14 +282,16 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
     result = checkConversionBetweenObjects(d.skipTypes(abstractInst), s.skipTypes(abstractInst), pointers)
   elif (targetBaseTyp.kind in IntegralTypes) and
       (srcBaseTyp.kind in IntegralTypes):
-    if targetTyp.kind == tyEnum and srcBaseTyp.kind == tyEnum:
+    if targetTyp.kind == tyEnum and srcBaseTyp.kind == tyEnum and
+        not sameType(targetTyp, srcBaseTyp):
       message(c.config, src.info, warnSuspiciousEnumConv, "suspicious code: enum to enum conversion")
     # `elif` would be incorrect here
     if targetTyp.kind == tyBool:
       discard "convOk"
     elif targetTyp.isOrdinalType:
       if src.kind in nkCharLit..nkUInt64Lit and
-          src.getInt notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp):
+          src.getInt notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp) and
+          targetTyp.kind notin {tyUInt..tyUInt64}:
         result = convNotInRange
       elif src.kind in nkFloatLit..nkFloat64Lit and
           (classify(src.floatVal) in {fcNan, fcNegInf, fcInf} or
@@ -554,15 +620,14 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
       n[1] = makeTypeSymNode(c, lhsType, n[1].info)
       lhsType = n[1].typ
   else:
-    if lhsType.base.kind == tyNone or
-        (c.inGenericContext > 0 and lhsType.base.containsGenericType):
+    if c.inGenericContext > 0 and lhsType.base.containsUnresolvedType:
       # BUGFIX: don't evaluate this too early: ``T is void``
       return
 
   result = isOpImpl(c, n, flags)
 
 proc semOpAux(c: PContext, n: PNode) =
-  const flags = {efDetermineType}
+  const flags = {efDetermineType, efAllowSymChoice}
   for i in 1..<n.len:
     var a = n[i]
     if a.kind == nkExprEqExpr and a.len == 2:
@@ -587,7 +652,14 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
 
 proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
   case n.kind
-  of nkCurly, nkBracket:
+  of nkCurly:
+    for i in 0..<n.len:
+      if n[i].kind == nkRange:
+        changeType(c, n[i][0], elemType(newType), check)
+        changeType(c, n[i][1], elemType(newType), check)
+      else:
+        changeType(c, n[i], elemType(newType), check)
+  of nkBracket:
     for i in 0..<n.len:
       changeType(c, n[i], elemType(newType), check)
   of nkPar, nkTupleConstr:
@@ -624,10 +696,16 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
       let value = n.intVal
       if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
         localError(c.config, n.info, "cannot convert " & $value &
-                                         " to " & typeToString(newType))
+                                         " to " & typeNameAndDesc(newType))
   of nkFloatLit..nkFloat64Lit:
     if check and not floatRangeCheck(n.floatVal, newType):
-      localError(c.config, n.info, errFloatToString % [$n.floatVal, typeToString(newType)])
+      localError(c.config, n.info, errFloatToString % [$n.floatVal, typeNameAndDesc(newType)])
+  of nkSym:
+    if check and n.sym.kind == skEnumField and not sameTypeOrNil(n.sym.typ, newType):
+      let value = n.sym.position
+      if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
+        localError(c.config, n.info, "cannot convert '" & n.sym.name.s &
+                                         "' to '" & typeNameAndDesc(newType) & "'")
   else: discard
   n.typ = newType
 
@@ -644,29 +722,41 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
 
 proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
   result = newNodeI(nkBracket, n.info)
-  result.typ = newTypeS(tyArray, c)
+  # nkBracket nodes can also be produced by the VM as seq constant nodes
+  # in which case, we cannot produce a new array type for the node,
+  # as this might lose type info even when the node has array type
+  let constructType = n.typ.isNil
   var expectedElementType, expectedIndexType: PType = nil
-  if expectedType != nil:
-    let expected = expectedType.skipTypes(abstractRange-{tyDistinct})
-    case expected.kind
+  var expectedBase: PType = nil
+  if constructType:
+    result.typ = newTypeS(tyArray, c)
+    rawAddSon(result.typ, nil)     # index type
+    if expectedType != nil:
+      expectedBase = expectedType.skipTypes(abstractRange-{tyDistinct})
+  else:
+    result.typ = n.typ
+    expectedBase = n.typ.skipTypes(abstractRange) # include tyDistinct this time
+  if expectedBase != nil:
+    case expectedBase.kind
     of tyArray:
-      expectedIndexType = expected[0]
-      expectedElementType = expected[1]
-    of tyOpenArray:
-      expectedElementType = expected[0]
+      expectedIndexType = expectedBase[0]
+      expectedElementType = expectedBase[1]
+    of tyOpenArray, tySequence:
+      # typed bracket expressions can also have seq type
+      expectedElementType = expectedBase[0]
     else: discard
-  rawAddSon(result.typ, nil)     # index type
   var
     firstIndex, lastIndex: Int128 = Zero
     indexType = getSysType(c.graph, n.info, tyInt)
     lastValidIndex = lastOrd(c.config, indexType)
   if n.len == 0:
-    rawAddSon(result.typ,
-      if expectedElementType != nil and
-          typeAllowed(expectedElementType, skLet, c) == nil:
-        expectedElementType
-      else:
-        newTypeS(tyEmpty, c)) # needs an empty basetype!
+    if constructType:
+      rawAddSon(result.typ,
+        if expectedElementType != nil and
+            typeAllowed(expectedElementType, skLet, c) == nil:
+          expectedElementType
+        else:
+          newTypeS(tyEmpty, c)) # needs an empty basetype!
     lastIndex = toInt128(-1)
   else:
     var x = n[0]
@@ -683,9 +773,13 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
         x = x[1]
 
     let yy = semExprWithType(c, x, {efTypeAllowed}, expectedElementType)
-    var typ = yy.typ
-    if expectedElementType == nil:
-      expectedElementType = typ
+    var typ: PType
+    if constructType:
+      typ = yy.typ
+      if expectedElementType == nil:
+        expectedElementType = typ
+    else:
+      typ = expectedElementType
     result.add yy
     #var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
     for i in 1..<n.len:
@@ -705,15 +799,20 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
 
       let xx = semExprWithType(c, x, {efTypeAllowed}, expectedElementType)
       result.add xx
-      typ = commonType(c, typ, xx.typ)
+      if constructType:
+        typ = commonType(c, typ, xx.typ)
       #n[i] = semExprWithType(c, x, {})
       #result.add fitNode(c, typ, n[i])
       inc(lastIndex)
-    addSonSkipIntLit(result.typ, typ, c.idgen)
+    if constructType:
+      addSonSkipIntLit(result.typ, typ, c.idgen)
     for i in 0..<result.len:
       result[i] = fitNode(c, typ, result[i], result[i].info)
-  result.typ.setIndexType makeRangeType(c, toInt64(firstIndex), toInt64(lastIndex), n.info,
-                                     indexType)
+  if constructType:
+    result.typ.setIndexType(
+      makeRangeType(c,
+        toInt64(firstIndex), toInt64(lastIndex),
+        n.info, indexType))
 
 proc fixAbstractType(c: PContext, n: PNode) =
   for i in 1..<n.len:
@@ -738,7 +837,7 @@ proc isUnresolvedSym(s: PSym): bool =
   result = s.kind == skGenericParam
   if not result and s.typ != nil:
     result = tfInferrableStatic in s.typ.flags or
-        (s.kind == skParam and s.typ.isMetaType) or
+        (s.kind == skParam and (s.typ.isMetaType or sfTemplateParam in s.flags)) or
         (s.kind == skType and
         s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
 
@@ -812,10 +911,13 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
 
 proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) =
   checkMinSonsLen(n, 1, c.config)
+  if n[0].typ == nil:
+    # n[0] might be erroring node in nimsuggest
+    return
   const
     FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
       mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
-      mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove,
+      mAppendSeqElem, mNewSeq, mShallowCopy, mDeepCopy, mMove,
       mWasMoved}
 
   template checkIfConverterCalled(c: PContext, n: PNode) =
@@ -914,7 +1016,8 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
 
     if callee.magic notin ctfeWhitelist: return
 
-    if callee.kind notin {skProc, skFunc, skConverter, skConst} or callee.isGenericRoutine:
+    if callee.kind notin {skProc, skFunc, skConverter, skConst} or
+        callee.isGenericRoutineStrict:
       return
 
     if n.typ != nil and typeAllowed(n.typ, skConst, c) != nil: return
@@ -971,7 +1074,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
 
   if result != nil:
     if result[0].kind != nkSym:
-      if not (efDetermineType in flags and c.inGenericContext > 0):
+      if not (c.inGenericContext > 0): # see generic context check in semOverloadedCall
         internalError(c.config, "semOverloadedCallAnalyseEffects")
       return
     let callee = result[0].sym
@@ -995,14 +1098,6 @@ proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
   result = initCandidate(c, t)
   matches(c, n, nOrig, result)
 
-proc bracketedMacro(n: PNode): PSym =
-  if n.len >= 1 and n[0].kind == nkSym:
-    result = n[0].sym
-    if result.kind notin {skMacro, skTemplate}:
-      result = nil
-  else:
-    result = nil
-
 proc finishOperand(c: PContext, a: PNode): PNode =
   if a.typ.isNil:
     result = c.semOperand(c, a, {efDetermineType})
@@ -1021,10 +1116,14 @@ proc finishOperand(c: PContext, a: PNode): PNode =
     localError(c.config, a.info, err)
   considerGenSyms(c, result)
 
-proc semFinishOperands(c: PContext; n: PNode) =
+proc semFinishOperands(c: PContext; n: PNode; isBracketExpr = false) =
   # this needs to be called to ensure that after overloading resolution every
-  # argument has been sem'checked:
-  for i in 1..<n.len:
+  # argument has been sem'checked
+
+  # skip the first argument for operands of `[]` since it may be an unresolved
+  # generic proc, which is handled in semMagic
+  let start = 1 + ord(isBracketExpr)
+  for i in start..<n.len:
     n[i] = finishOperand(c, n[i])
 
 proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
@@ -1047,10 +1146,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
   of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType)
   of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType)
   else:
-    if callee.magic notin {mArrGet, mArrPut, mNBindSym}:
-      # calls to `[]` can be explicit generic instantiations,
-      # don't sem every operand now, leave it to semmagic
-      semFinishOperands(c, result)
+    semFinishOperands(c, result, isBracketExpr = callee.magic in {mArrGet, mArrPut})
     activate(c, result)
     fixAbstractType(c, result)
     analyseIfAddressTakenInCall(c, result)
@@ -1061,7 +1157,8 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
           not (result.typ.kind == tySequence and result.elementType.kind == tyEmpty):
         liftTypeBoundOps(c, result.typ, n.info)
     #result = patchResolvedTypeBoundOp(c, result)
-  if c.matchedConcept == nil:
+  if c.matchedConcept == nil and (c.inTypeofContext == 0 or callee.magic != mNone):
+    # don't fold calls in concepts and typeof
     result = evalAtCompileTime(c, result)
 
 proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
@@ -1078,6 +1175,11 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
       result.flags.incl nfExplicitCall
       for i in 1..<n.len: result.add n[i]
       return semExpr(c, result, flags, expectedType)
+    elif n0.typ.kind == tyFromExpr and c.inGenericContext > 0:
+      # don't make assumptions, entire expression needs to be tyFromExpr
+      result = semGenericStmt(c, n)
+      result.typ = makeTypeFromExpr(c, result.copyTree)
+      return
     else:
       n[0] = n0
   else:
@@ -1085,11 +1187,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
     let t = n[0].typ
     if t != nil and t.kind in {tyVar, tyLent}:
       n[0] = newDeref(n[0])
-    elif n[0].kind == nkBracketExpr:
-      let s = bracketedMacro(n[0])
-      if s != nil:
-        setGenericParams(c, n[0], s.ast[genericParamsPos])
-        return semDirectOp(c, n, flags, expectedType)
     elif isSymChoice(n[0]) and nfDotField notin n.flags:
       # overloaded generic procs e.g. newSeq[int] can end up here
       return semDirectOp(c, n, flags, expectedType)
@@ -1418,20 +1515,34 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
 
 proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode =
   case t.kind
-  of tyTypeParamsHolders:
+  of tyGenericInst:
     result = readTypeParameter(c, t, i, n.info)
     if result == c.graph.emptyNode:
-      result = n
-      n.typ = makeTypeFromExpr(c, n.copyTree)
+      if c.inGenericContext > 0:
+        result = semGenericStmt(c, n)
+        result.typ = makeTypeFromExpr(c, result.copyTree)
+      else:
+        result = nil
   of tyUserTypeClasses:
     if t.isResolvedUserTypeClass:
       result = readTypeParameter(c, t, i, n.info)
+    elif c.inGenericContext > 0:
+      result = semGenericStmt(c, n)
+      result.typ = makeTypeFromExpr(c, copyTree(result))
     else:
-      n.typ = makeTypeFromExpr(c, copyTree(n))
-      result = n
-  of tyGenericParam, tyAnything:
-    n.typ = makeTypeFromExpr(c, copyTree(n))
-    result = n
+      result = nil
+  of tyGenericBody, tyCompositeTypeClass:
+    if c.inGenericContext > 0:
+      result = readTypeParameter(c, t, i, n.info)
+      if result != nil:
+        # generic parameter exists, stop here but delay until instantiation
+        result = semGenericStmt(c, n)
+        result.typ = makeTypeFromExpr(c, copyTree(result))
+    else:
+      result = nil
+  elif c.inGenericContext > 0 and t.containsUnresolvedType:
+    result = semGenericStmt(c, n)
+    result.typ = makeTypeFromExpr(c, copyTree(result))
   else:
     result = nil
 
@@ -1595,18 +1706,20 @@ proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode =
   result.add(newIdentNode(ident, n.info))
   for s in n: result.add s
 
-proc semDeref(c: PContext, n: PNode): PNode =
+proc semDeref(c: PContext, n: PNode, flags: TExprFlags): PNode =
   checkSonsLen(n, 1, c.config)
   n[0] = semExprWithType(c, n[0])
   let a = getConstExpr(c.module, n[0], c.idgen, c.graph)
   if a != nil:
-    if a.kind == nkNilLit:
+    if a.kind == nkNilLit and efInTypeof notin flags:
       localError(c.config, n.info, "nil dereference is not allowed")
     n[0] = a
   result = n
   var t = skipTypes(n[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink, tyOwned})
   case t.kind
   of tyRef, tyPtr: n.typ = t.elementType
+  of tyMetaTypes, tyFromExpr:
+    n.typ = makeTypeFromExpr(c, n.copyTree)
   else: result = nil
   #GlobalError(n[0].info, errCircumNeedsPointer)
 
@@ -1629,16 +1742,17 @@ proc maybeInstantiateGeneric(c: PContext, n: PNode, s: PSym): PNode =
     result = explicitGenericInstantiation(c, n, s)
     if result == n:
       n[0] = copyTree(result[0])
-    else:
-      n[0] = result
 
 proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if not a built-in subscript operator; also called for the
   ## checking of assignments
   result = nil
   if n.len == 1:
-    let x = semDeref(c, n)
+    let x = semDeref(c, n, flags)
     if x == nil: return nil
+    if x.typ.kind == tyFromExpr:
+      # depends on generic type
+      return x
     result = newNodeIT(nkDerefExpr, x.info, x.typ)
     result.add(x[0])
     return
@@ -1703,7 +1817,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result = nil
   else:
     let s = if n[0].kind == nkSym: n[0].sym
-            elif n[0].kind in nkSymChoices: n[0][0].sym
+            elif n[0].kind in nkSymChoices + {nkOpenSym}: n[0][0].sym
             else: nil
     if s != nil:
       case s.kind
@@ -1784,6 +1898,8 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
     else:
       localError(c.config, n.info, errExprHasNoAddress)
   result = newNodeIT(nkHiddenAddr, n.info, if n.typ.kind in {tyVar, tyLent}: n.typ else: makePtrType(c, n.typ))
+  if n.typ.kind in {tyVar, tyLent}:
+    n.typ = n.typ.elementType
   result.add(n)
 
 proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
@@ -1910,7 +2026,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
       result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "[]="))
       result.add(n[1])
       if mode == noOverloadedSubscript:
-        bracketNotFoundError(c, result)
+        bracketNotFoundError(c, result, {})
         return errorNode(c, n)
       else:
         result = semExprNoType(c, result)
@@ -1957,7 +2073,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
         if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass:
           rhsTyp = rhsTyp.last
         if lhs.sym.typ.kind == tyAnything:
-          rhsTyp = rhsTyp.skipIntLit(c.idgen)
+          rhsTyp = rhsTyp.skipTypes({tySink}).skipIntLit(c.idgen)
         if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}:
           internalAssert c.config, c.p.resultSym != nil
           # Make sure the type is valid for the result variable
@@ -2139,6 +2255,8 @@ proc lookUpForDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
     result = n.sym
   of nkOpenSymChoice, nkClosedSymChoice:
     result = n[0].sym
+  of nkOpenSym:
+    result = lookUpForDeclared(c, n[0], onlyCurrentScope)
   else:
     localError(c.config, n.info, "identifier expected, but got: " & renderTree(n))
     result = nil
@@ -2426,7 +2544,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
   # codegen would fail:
   if sfCompilerProc in result.flags:
     result.flags.excl {sfCompilerProc, sfExportc, sfImportc}
-    result.loc.r = ""
+    result.loc.snippet = ""
 
 proc setMs(n: PNode, s: PSym): PNode =
   result = n
@@ -2591,13 +2709,16 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
   var typ = commonTypeBegin
   if n.len in 1..2 and n[0].kind == nkElifBranch and (
       n.len == 1 or n[1].kind == nkElse):
-    let exprNode = n[0][0]
+    var exprNode = n[0][0]
+    if exprNode.kind == nkOpenSym:
+      exprNode = exprNode[0]
     if exprNode.kind == nkIdent:
       whenNimvm = lookUp(c, exprNode).magic == mNimvm
     elif exprNode.kind == nkSym:
       whenNimvm = exprNode.sym.magic == mNimvm
     if whenNimvm: n.flags.incl nfLL
 
+  var cannotResolve = false
   for i in 0..<n.len:
     var it = n[i]
     case it.kind
@@ -2608,6 +2729,19 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
           it[1] = semExpr(c, it[1], flags)
           typ = commonType(c, typ, it[1].typ)
         result = n # when nimvm is not elimited until codegen
+      elif c.inGenericContext > 0:
+        let e = semExprWithType(c, it[0])
+        if e.typ.kind == tyFromExpr:
+          it[0] = makeStaticExpr(c, e)
+          cannotResolve = true
+        else:
+          it[0] = forceBool(c, e)
+          let val = getConstExpr(c.module, it[0], c.idgen, c.graph)
+          if val == nil or val.kind != nkIntLit:
+            cannotResolve = true
+          elif not cannotResolve and val.intVal != 0 and result == nil:
+            setResult(it[1])
+            return # we're not in nimvm and we already have a result
       else:
         let e = forceBool(c, semConstExpr(c, it[0]))
         if e.kind != nkIntLit:
@@ -2619,13 +2753,21 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
           return # we're not in nimvm and we already have a result
     of nkElse, nkElseExpr:
       checkSonsLen(it, 1, c.config)
-      if result == nil or whenNimvm:
+      if cannotResolve:
+        discard
+      elif result == nil or whenNimvm:
         if semCheck:
           it[0] = semExpr(c, it[0], flags)
           typ = commonType(c, typ, it[0].typ)
+          if typ != nil and typ.kind != tyUntyped:
+            it[0] = fitNode(c, typ, it[0], it[0].info)
         if result == nil:
           result = it[0]
     else: illFormedAst(n, c.config)
+  if cannotResolve:
+    result = semGenericStmt(c, n)
+    result.typ = makeTypeFromExpr(c, result.copyTree)
+    return
   if result == nil:
     result = newNodeI(nkEmpty, n.info)
   if whenNimvm:
@@ -2779,7 +2921,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
       n[i][1].typ = errorType(c)
 
     var f = newSymS(skField, n[i][0], c)
-    f.typ = skipIntLit(n[i][1].typ, c.idgen)
+    f.typ = skipIntLit(n[i][1].typ.skipTypes({tySink}), c.idgen)
     f.position = i
     rawAddSon(typ, f.typ)
     typ.n.add newSymNode(f)
@@ -2805,7 +2947,7 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedT
       # `const foo = [(1, {}), (2, {false})]`,
       # `const foo = if true: (0, nil) else: (1, new(int))`
       n[i] = fitNode(c, expectedElemType, n[i], n[i].info)
-    addSonSkipIntLit(typ, n[i].typ, c.idgen)
+    addSonSkipIntLit(typ, n[i].typ.skipTypes({tySink}), c.idgen)
   result.typ = typ
 
 include semobjconstr
@@ -2910,19 +3052,42 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp
   else:
     result = tupexp
 
-proc shouldBeBracketExpr(n: PNode): bool =
-  result = false
+proc isExplicitGenericCall(c: PContext, n: PNode): bool =
+  ## checks if a call node `n` is a routine call with explicit generic params
+  ## 
+  ## the callee node needs to be either an nkBracketExpr or a call to a
+  ## symchoice of `[]` in which case it will be transformed into nkBracketExpr
+  ## 
+  ## the LHS of the bracket expr has to either be a symchoice or resolve to
+  ## a routine symbol
+  template checkCallee(n: PNode) =
+    # check subscript LHS, `n` must be mutable
+    if isSymChoice(n):
+      result = true
+    else:
+      let s = qualifiedLookUp(c, n, {})
+      if s != nil and s.kind in routineKinds:
+        result = true
+        n = semSymGenericInstantiation(c, n, s)
   assert n.kind in nkCallKinds
+  result = false
   let a = n[0]
-  if a.kind in nkCallKinds:
+  case a.kind
+  of nkBracketExpr:
+    checkCallee(a[0])
+  of nkCallKinds:
     let b = a[0]
     if b.kind in nkSymChoices:
-      for i in 0..<b.len:
-        if b[i].kind == nkSym and b[i].sym.magic == mArrGet:
-          let be = newNodeI(nkBracketExpr, n.info)
+      let name = b.getPIdent
+      if name != nil and name.s == "[]":
+        checkCallee(a[1])
+        if result:
+          # transform callee into normal bracket expr, only on success
+          let be = newNodeI(nkBracketExpr, a.info)
           for i in 1..<a.len: be.add(a[i])
           n[0] = be
-          return true
+  else:
+    result = false
 
 proc asBracketExpr(c: PContext; n: PNode): PNode =
   proc isGeneric(c: PContext; n: PNode): bool =
@@ -2943,6 +3108,18 @@ proc asBracketExpr(c: PContext; n: PNode): PNode =
           return result
   return nil
 
+proc isOpenArraySym(x: PNode): bool =
+  var x = x
+  while true:
+    case x.kind
+    of {nkAddr, nkHiddenAddr}:
+      x = x[0]
+    of {nkHiddenStdConv, nkHiddenDeref}:
+      x = x[1]
+    else:
+      break
+  result = x.kind == nkSym
+
 proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode) =
   # This takes care of complicated signatures such as:
   # proc foo(a: int, b = a)
@@ -2960,10 +3137,17 @@ proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode)
   # duty is activated by returning a non-nil value. The caller is responsible
   # for replacing the input to the function with the returned non-nil value.
   # (which is the hoisted symbol)
-  if defExpr.kind == nkSym and defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym:
+  if defExpr.kind == nkSym and defExpr.sym.kind == skParam and
+      (defExpr.sym.owner == call[0].sym or
+        # symbol was resolved before proc was instantiated:
+        (sfFromGeneric in call[0].sym.flags and
+          defExpr.sym.owner == call[0].sym.instantiatedFrom)):
     let paramPos = defExpr.sym.position + 1
 
-    if call[paramPos].skipAddr.kind != nkSym:
+    if call[paramPos].skipAddr.kind != nkSym and not (
+      skipTypes(call[paramPos].typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
+      isOpenArraySym(call[paramPos])
+    ):
       let hoistedVarSym = newSym(skLet, getIdent(c.graph.cache, genPrefix), c.idgen,
                                  c.p.owner, letSection.info, c.p.owner.options)
       hoistedVarSym.typ = call[paramPos].typ
@@ -2989,7 +3173,7 @@ proc getNilType(c: PContext): PType =
     result.align = c.config.target.ptrSize.int16
     c.nilTypeCache = result
 
-proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode =
+proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym; flags: TExprFlags): PNode =
   var o: TOverloadIter = default(TOverloadIter)
   var i = 0
   var a = initOverloadIter(o, c, n)
@@ -3002,7 +3186,7 @@ proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode =
   if i <= 1:
     if sfGenSym notin s.flags:
       result = newSymNode(s, info)
-      markUsed(c, info, s)
+      markUsed(c, info, s, efInCall notin flags)
       onUse(info, s)
     else:
       result = n
@@ -3027,30 +3211,30 @@ proc resolveIdentToSym(c: PContext, n: PNode, resultNode: var PNode,
                        flags: TExprFlags, expectedType: PType): PSym =
   # result is nil on error or if a node that can't produce a sym is resolved
   let ident = considerQuotedIdent(c, n)
-  if expectedType != nil and (
-      let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
-      expected.kind == tyEnum):
-    let nameId = ident.id
-    for f in expected.n:
-      if f.kind == nkSym and f.sym.name.id == nameId:
-        return f.sym
   var filter = {low(TSymKind)..high(TSymKind)}
-  if efNoEvaluateGeneric in flags:
+  if efNoEvaluateGeneric in flags or expectedType != nil:
     # `a[...]` where `a` is a module or package is not possible
     filter.excl {skModule, skPackage}
-  let candidates = lookUpCandidates(c, ident, filter)
+  let includePureEnum = expectedType != nil and
+    expectedType.skipTypes(abstractRange-{tyDistinct}).kind == tyEnum
+  let candidates = lookUpCandidates(c, ident, filter,
+    includePureEnum = includePureEnum)
   if candidates.len == 0:
     result = errorUndeclaredIdentifierHint(c, ident, n.info)
   elif candidates.len == 1 or {efNoEvaluateGeneric, efInCall} * flags != {}:
     # unambiguous, or we don't care about ambiguity
     result = candidates[0]
   else:
-    # ambiguous symbols have 1 last chance as a symchoice,
-    # but type symbols cannot participate in symchoices
+    # ambiguous symbols have 1 last chance as a symchoice
     var choice = newNodeIT(nkClosedSymChoice, n.info, newTypeS(tyNone, c))
-    for c in candidates:
-      if c.kind notin {skType, skModule, skPackage}:
-        choice.add newSymNode(c, n.info)
+    for cand in candidates:
+      case cand.kind
+      of skModule, skPackage:
+        discard
+      of skType:
+        choice.add newSymNodeTypeDesc(cand, c.idgen, n.info)
+      else:
+        choice.add newSymNode(cand, n.info)
     if choice.len == 0:
       # we know candidates.len > 1, we just couldn't put any in a symchoice
       errorUseQualifier(c, n.info, candidates)
@@ -3126,46 +3310,35 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
       if optOwnedRefs in c.config.globalOptions:
         result.typ = makeVarType(c, result.typ, tyOwned)
     of skEnumField:
-      result = enumFieldSymChoice(c, n, s)
+      result = enumFieldSymChoice(c, n, s, flags)
     else:
       result = semSym(c, n, s, flags)
     if isSymChoice(result):
       result = semSymChoice(c, result, flags, expectedType)
   of nkClosedSymChoice, nkOpenSymChoice:
-    result = semSymChoice(c, result, flags, expectedType)
+    result = semSymChoice(c, n, flags, expectedType)
   of nkSym:
     let s = n.sym
-    if nfOpenSym in n.flags:
-      let id = newIdentNode(s.name, n.info)
-      c.isAmbiguous = false
-      let s2 = qualifiedLookUp(c, id, {})
-      if s2 != nil and s2 != s and not c.isAmbiguous:
-        # only consider symbols defined under current proc:
-        var o = s2.owner
-        while o != nil:
-          if o == c.p.owner:
-            if genericsOpenSym in c.features:
-              result = semExpr(c, id, flags, expectedType)
-              return
-            else:
-              message(c.config, n.info, warnGenericsIgnoredInjection,
-                "a new symbol '" & s.name.s & "' has been injected during " &
-                "instantiation of " & c.p.owner.name.s & ", " &
-                "however " & getSymRepr(c.config, s) & " captured at " &
-                "the proc declaration will be used instead; " &
-                "either enable --experimental:genericsOpenSym to use the " &
-                "injected symbol or `bind` this captured symbol explicitly")
-              break
-          o = o.owner
+    if nfDisabledOpenSym in n.flags:
+      let override = genericsOpenSym in c.features
+      let res = semOpenSym(c, n, flags, expectedType,
+        warnDisabled = not override)
+      if res != nil:
+        assert override
+        return res
     # because of the changed symbol binding, this does not mean that we
     # don't have to check the symbol for semantics here again!
     result = semSym(c, n, s, flags)
+  of nkOpenSym:
+    assert n.len == 1
+    let inner = n[0]
+    result = semOpenSym(c, inner, flags, expectedType)
   of nkEmpty, nkNone, nkCommentStmt, nkType:
     discard
   of nkNilLit:
     if result.typ == nil:
       result.typ = getNilType(c)
-      if expectedType != nil:
+      if expectedType != nil and expectedType.kind notin {tyUntyped, tyTyped}:
         var m = newCandidate(c, result.typ)
         if typeRel(m, expectedType, result.typ) >= isSubtype:
           result.typ = expectedType
@@ -3247,12 +3420,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
       of skType:
         # XXX think about this more (``set`` procs)
         let ambig = c.isAmbiguous
-        if not (n[0].kind in {nkClosedSymChoice, nkOpenSymChoice, nkIdent} and ambig) and n.len == 2:
+        if not (n[0].kind in nkSymChoices + {nkIdent, nkDotExpr} and ambig) and n.len == 2:
           result = semConv(c, n, flags, expectedType)
-        elif ambig and n.len == 1:
-          errorUseQualifier(c, n.info, s)
         elif n.len == 1:
-          result = semObjConstr(c, n, flags, expectedType)
+          if ambig:
+            errorUseQualifier(c, n.info, s)
+          else:
+            result = semObjConstr(c, n, flags, expectedType)
         elif s.magic == mNone: result = semDirectOp(c, n, flags, expectedType)
         else: result = semMagic(c, n, s, flags, expectedType)
       of skProc, skFunc, skMethod, skConverter, skIterator:
@@ -3261,11 +3435,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
       else:
         #liMessage(n.info, warnUser, renderTree(n));
         result = semIndirectOp(c, n, flags, expectedType)
-    elif (n[0].kind == nkBracketExpr or shouldBeBracketExpr(n)) and
-        isSymChoice(n[0][0]):
-      # indirectOp can deal with explicit instantiations; the fixes
-      # the 'newSeq[T](x)' bug
-      setGenericParams(c, n[0], nil)
+    elif isExplicitGenericCall(c, n): # this modifies `n` if true
       result = semDirectOp(c, n, flags, expectedType)
     elif nfDotField in n.flags:
       result = semDirectOp(c, n, flags, expectedType)
@@ -3330,7 +3500,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
     result = semArrayConstr(c, n, flags, expectedType)
   of nkObjConstr: result = semObjConstr(c, n, flags, expectedType)
   of nkLambdaKinds: result = semProcAux(c, n, skProc, lambdaPragmas, flags)
-  of nkDerefExpr: result = semDeref(c, n)
+  of nkDerefExpr: result = semDeref(c, n, flags)
   of nkAddr:
     result = n
     checkSonsLen(n, 1, c.config)
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index f7da4ea75..80144ccc0 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -420,14 +420,17 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
       result = newIntNodeT(toInt128(getFloat(a)), n, idgen, g)
     of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
       var val = a.getOrdValue
-      if check: rangeCheck(n, val, g)
-      result = newIntNodeT(val, n, idgen, g)
       if dstTyp.kind in {tyUInt..tyUInt64}:
+        result = newIntNodeT(maskBytes(val, int getSize(g.config, dstTyp)), n, idgen, g)
         result.transitionIntKind(nkUIntLit)
+      else:
+        if check: rangeCheck(n, val, g)
+        result = newIntNodeT(val, n, idgen, g)
     else:
       result = a
       result.typ = n.typ
-    if check and result.kind in {nkCharLit..nkUInt64Lit}:
+    if check and result.kind in {nkCharLit..nkUInt64Lit} and
+          dstTyp.kind notin {tyUInt..tyUInt64}:
       rangeCheck(n, getInt(result), g)
   of tyFloat..tyFloat64:
     case srcTyp.kind
@@ -701,10 +704,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
     except DivByZeroDefect:
       localError(g.config, n.info, "division by zero")
   of nkAddr:
-    var a = getConstExpr(m, n[0], idgen, g)
-    if a != nil:
-      result = n
-      n[0] = a
+    result = nil # don't fold paths containing nkAddr
   of nkBracket, nkCurly:
     result = copyNode(n)
     for son in n.items:
@@ -750,6 +750,8 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
     if leValueConv(n[1], a) and leValueConv(a, n[2]):
       result = a              # a <= x and x <= b
       result.typ = n.typ
+    elif n.typ.kind in {tyUInt..tyUInt64}:
+      discard "don't check uints"
     else:
       localError(g.config, n.info,
         "conversion from $1 to $2 is invalid" %
@@ -771,7 +773,8 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
   of nkCast:
     var a = getConstExpr(m, n[1], idgen, g)
     if a == nil: return
-    if n.typ != nil and n.typ.kind in NilableTypes:
+    if n.typ != nil and n.typ.kind in NilableTypes and
+        not (n.typ.kind == tyProc and a.typ.kind == tyProc):
       # we allow compile-time 'cast' for pointer types:
       result = a
       result.typ = n.typ
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 638b4311b..2639aba6c 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -61,6 +61,7 @@ template canOpenSym(s): bool =
 
 proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
                           ctx: var GenericCtx; flags: TSemGenericFlags,
+                          isAmbiguous: bool,
                           fromDotExpr=false): PNode =
   result = nil
   semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody)
@@ -72,9 +73,15 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
         result.transitionSonsKind(nkClosedSymChoice)
     else:
       result = symChoice(c, n, s, scOpen)
-      if result.kind == nkSym and canOpenSym(result.sym):
-        result.flags.incl nfOpenSym
-        result.typ = nil
+      if canOpenSym(s):
+        if openSym in c.features:
+          if result.kind == nkSym:
+            result = newOpenSym(result)
+          else:
+            result.typ = nil
+        else:
+          result.flags.incl nfDisabledOpenSym
+          result.typ = nil
   case s.kind
   of skUnknown:
     # Introduced in this pass! Leave it as an identifier.
@@ -98,13 +105,28 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
     if s.typ != nil and s.typ.kind == tyStatic:
       if s.typ.n != nil:
         result = s.typ.n
+      elif c.inGenericContext > 0 and withinConcept notin flags:
+        # don't leave generic param as identifier node in generic type,
+        # sigmatch will try to instantiate generic type AST without all params
+        # fine to give a symbol node a generic type here since
+        # we are in a generic context and `prepareNode` will be called
+        result = newSymNodeTypeDesc(s, c.idgen, n.info)
+        if canOpenSym(result.sym):
+          if openSym in c.features:
+            result = newOpenSym(result)
+          else:
+            result.flags.incl nfDisabledOpenSym
+            result.typ = nil
       else:
         result = n
     else:
       result = newSymNodeTypeDesc(s, c.idgen, n.info)
       if canOpenSym(result.sym):
-        result.flags.incl nfOpenSym
-        result.typ = nil
+        if openSym in c.features:
+          result = newOpenSym(result)
+        else:
+          result.flags.incl nfDisabledOpenSym
+          result.typ = nil
     onUse(n.info, s)
   of skParam:
     result = n
@@ -112,18 +134,41 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
   of skType:
     if (s.typ != nil) and
        (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
+      if isAmbiguous:
+        # ambiguous types should be symchoices since lookup behaves
+        # differently for them in regular expressions
+        maybeDotChoice(c, n, s, fromDotExpr)
+        return
       result = newSymNodeTypeDesc(s, c.idgen, n.info)
       if canOpenSym(result.sym):
-        result.flags.incl nfOpenSym
-        result.typ = nil
+        if openSym in c.features:
+          result = newOpenSym(result)
+        else:
+          result.flags.incl nfDisabledOpenSym
+          result.typ = nil
+    elif c.inGenericContext > 0 and withinConcept notin flags:
+      # don't leave generic param as identifier node in generic type,
+      # sigmatch will try to instantiate generic type AST without all params
+      # fine to give a symbol node a generic type here since
+      # we are in a generic context and `prepareNode` will be called
+      result = newSymNodeTypeDesc(s, c.idgen, n.info)
+      if canOpenSym(result.sym):
+        if openSym in c.features:
+          result = newOpenSym(result)
+        else:
+          result.flags.incl nfDisabledOpenSym
+          result.typ = nil
     else:
       result = n
     onUse(n.info, s)
   else:
     result = newSymNode(s, n.info)
     if canOpenSym(result.sym):
-      result.flags.incl nfOpenSym
-      result.typ = nil
+      if openSym in c.features:
+        result = newOpenSym(result)
+      else:
+        result.flags.incl nfDisabledOpenSym
+        result.typ = nil
     onUse(n.info, s)
 
 proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
@@ -145,7 +190,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
     elif s.isMixedIn:
       result = symChoice(c, n, s, scForceOpen)
     else:
-      result = semGenericStmtSymbol(c, n, s, ctx, flags)
+      result = semGenericStmtSymbol(c, n, s, ctx, flags, amb)
   # else: leave as nkIdent
 
 proc newDot(n, b: PNode): PNode =
@@ -161,10 +206,11 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
 
   let luf = if withinMixin notin flags: {checkUndeclared, checkModule} else: {checkModule}
 
+  c.isAmbiguous = false
   var s = qualifiedLookUp(c, n, luf)
   if s != nil:
     isMacro = s.kind in {skTemplate, skMacro}
-    result = semGenericStmtSymbol(c, n, s, ctx, flags)
+    result = semGenericStmtSymbol(c, n, s, ctx, flags, c.isAmbiguous)
   else:
     n[0] = semGenericStmt(c, n[0], flags, ctx)
     result = n
@@ -178,24 +224,21 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
       isMacro = s.kind in {skTemplate, skMacro}
       if withinBind in flags or s.id in ctx.toBind:
         if s.kind == skType: # don't put types in sym choice
-          result = newDot(result, semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true))
+          var ambig = false
+          if candidates.len > 1:
+            let s2 = searchInScopes(c, ident, ambig)
+          result = newDot(result, semGenericStmtSymbol(c, n, s, ctx, flags,
+            isAmbiguous = ambig, fromDotExpr = true))
         else:
           result = newDot(result, symChoice(c, n, s, scClosed))
       elif s.isMixedIn:
         result = newDot(result, symChoice(c, n, s, scForceOpen))
       else:
+        var ambig = false
         if s.kind == skType and candidates.len > 1:
-          var ambig = false
-          let s2 = searchInScopes(c, ident, ambig) 
-          if ambig:
-            # this is a type conversion like a.T where T is ambiguous with
-            # other types or routines
-            # in regular code, this never considers a type conversion and
-            # skips to routine overloading
-            # so symchoices are used which behave similarly with type symbols
-            result = newDot(result, symChoice(c, n, s, scForceOpen))
-            return
-        let syms = semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true)
+          discard searchInScopes(c, ident, ambig)
+        let syms = semGenericStmtSymbol(c, n, s, ctx, flags,
+          isAmbiguous = ambig, fromDotExpr = true)
         result = newDot(result, syms)
 
 proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
@@ -262,7 +305,9 @@ proc semGenericStmt(c: PContext, n: PNode,
     # check if it is an expression macro:
     checkMinSonsLen(n, 1, c.config)
     let fn = n[0]
+    c.isAmbiguous = false
     var s = qualifiedLookUp(c, fn, {})
+    let ambig = c.isAmbiguous
     if s == nil and
         {withinMixin, withinConcept}*flags == {} and
         fn.kind in {nkIdent, nkAccQuoted} and
@@ -315,7 +360,12 @@ proc semGenericStmt(c: PContext, n: PNode,
       of skType:
         # bad hack for generics:
         if (s.typ != nil) and (s.typ.kind != tyGenericParam):
-          result[0] = newSymNodeTypeDesc(s, c.idgen, fn.info)
+          if ambig:
+            # ambiguous types should be symchoices since lookup behaves
+            # differently for them in regular expressions
+            result[0] = sc
+          else:
+            result[0] = newSymNodeTypeDesc(s, c.idgen, fn.info)
           onUse(fn.info, s)
           first = 1
       else:
@@ -563,7 +613,8 @@ proc semGenericStmt(c: PContext, n: PNode,
       else:
         body = getBody(c.graph, s)
     else: body = n[bodyPos]
-    n[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
+    let bodyFlags = if n.kind == nkTemplateDef: flags + {withinMixin} else: flags
+    n[bodyPos] = semGenericStmtScope(c, body, bodyFlags, ctx)
     closeScope(c)
   of nkPragma, nkPragmaExpr: discard
   of nkExprColonExpr, nkExprEqExpr:
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index e9b46c382..1bc6d31a2 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -53,11 +53,14 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TypeMapping): PS
           if q.typ.kind != tyCompositeTypeClass:
             localError(c.config, a.info, errCannotInstantiateX % s.name.s)
           t = errorType(c)
-      elif t.kind in {tyGenericParam, tyConcept}:
+      elif t.kind in {tyGenericParam, tyConcept, tyFromExpr}:
         localError(c.config, a.info, errCannotInstantiateX % q.name.s)
         t = errorType(c)
-      elif isUnresolvedStatic(t) and c.inGenericContext == 0 and
-          c.matchedConcept == nil:
+      elif isUnresolvedStatic(t) and (q.typ.kind == tyStatic or
+            (q.typ.kind == tyGenericParam and
+              q.typ.genericParamHasConstraints and
+              q.typ.genericConstraint.kind == tyStatic)) and
+          c.inGenericContext == 0 and c.matchedConcept == nil:
         # generic/concept type bodies will try to instantiate static values but
         # won't actually use them
         localError(c.config, a.info, errCannotInstantiateX % q.name.s)
@@ -250,9 +253,15 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
     var typeToFit = resulti
 
     let needsStaticSkipping = resulti.kind == tyFromExpr
+    let needsTypeDescSkipping = resulti.kind == tyTypeDesc and tfUnresolved in resulti.flags
+    if resulti.kind == tyFromExpr:
+      resulti.flags.incl tfNonConstExpr
     result[i] = replaceTypeVarsT(cl, resulti)
     if needsStaticSkipping:
       result[i] = result[i].skipTypes({tyStatic})
+    if needsTypeDescSkipping:
+      result[i] = result[i].skipTypes({tyTypeDesc})
+      typeToFit = result[i]
 
     # ...otherwise, we use the instantiated type in `fitNode`
     if (typeToFit.kind != tyTypeDesc or typeToFit.base.kind != tyNone) and
@@ -270,9 +279,10 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
     # call head symbol, because this leads to infinite recursion.
     if oldParam.ast != nil:
       var def = oldParam.ast.copyTree
-      if def.kind in nkCallKinds:
-        for i in 1..<def.len:
-          def[i] = replaceTypeVarsN(cl, def[i], 1)
+      if def.typ.kind == tyFromExpr:
+        def.typ.flags.incl tfNonConstExpr
+      if not isIntLit(def.typ):
+        def = prepareNode(cl, def)
 
       # allow symchoice since node will be fit later
       # although expectedType should cover it
@@ -289,6 +299,8 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
         # the user calls an explicit instantiation of the proc (this is
         # the only way the default value might be inserted).
         param.ast = errorNode(c, def)
+        # we know the node is empty, we need the actual type for error message
+        param.ast.typ = def.typ
       else:
         param.ast = fitNodePostMatch(c, typeToFit, converted)
       param.typ = result[i]
@@ -312,6 +324,22 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
   prc.typ = result
   popInfoContext(c.config)
 
+proc instantiateOnlyProcType(c: PContext, pt: TypeMapping, prc: PSym, info: TLineInfo): PType =
+  # instantiates only the type of a given proc symbol
+  # used by sigmatch for explicit generics
+  # wouldn't be needed if sigmatch could handle complex cases,
+  # examples are in texplicitgenerics
+  # might be buggy, see rest of generateInstance if problems occur
+  let fakeSym = copySym(prc, c.idgen)
+  incl(fakeSym.flags, sfFromGeneric)
+  fakeSym.instantiatedFrom = prc
+  openScope(c)
+  for s in instantiateGenericParamList(c, prc.ast[genericParamsPos], pt):
+    addDecl(c, s)
+  instantiateProcType(c, pt, fakeSym, info)
+  closeScope(c)
+  result = fakeSym.typ
+
 proc fillMixinScope(c: PContext) =
   var p = c.p
   while p != nil:
@@ -342,7 +370,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
   # generates an instantiated proc
   if c.instCounter > 50:
     globalError(c.config, info, "generic instantiation too nested")
-  inc(c.instCounter)
+  inc c.instCounter
+  defer: dec c.instCounter
   # careful! we copy the whole AST including the possibly nil body!
   var n = copyTree(fn.ast)
   # NOTE: for access of private fields within generics from a different module
@@ -396,6 +425,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
   for _, param in paramTypes(result.typ):
     entry.concreteTypes[i] = param
     inc i
+  #echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " ", entry.concreteTypes.len
   if tfTriggersCompileTime in result.typ.flags:
     incl(result.flags, sfCompileTime)
   n[genericParamsPos] = c.graph.emptyNode
@@ -424,7 +454,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
     if result.magic notin {mSlice, mTypeOf}:
       # 'toOpenArray' is special and it is allowed to return 'openArray':
       paramsTypeCheck(c, result.typ)
+    #echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " <-- NEW PROC!", " ", entry.concreteTypes.len
   else:
+    #echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " <-- CACHED! ", typeToString(oldPrc.typ), " ", entry.concreteTypes.len
     result = oldPrc
   popProcCon(c)
   popInfoContext(c.config)
@@ -433,7 +465,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
   popOwner(c)
   c.currentScope = oldScope
   discard c.friendModules.pop()
-  dec(c.instCounter)
   c.matchedConcept = oldMatchedConcept
   if result.kind == skMethod: finishMethod(c, result)
 
diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim
index 4aab216c7..727f36470 100644
--- a/compiler/semmacrosanity.nim
+++ b/compiler/semmacrosanity.nim
@@ -51,6 +51,7 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
   of nkObjConstr:
     let x = t.skipTypes(abstractPtrs)
     n.typ = t
+    n[0].typ = t
     for i in 1..<n.len:
       var j = i-1
       let field = x.ithField(j)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 8db62a9c8..a12e933e7 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -49,8 +49,12 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
     else:
       m = mode.intVal
   result = newNodeI(nkTypeOfExpr, n.info)
+  inc c.inTypeofContext
+  defer: dec c.inTypeofContext # compiles can raise an exception
   let typExpr = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
   result.add typExpr
+  if typExpr.typ.kind == tyFromExpr:
+    typExpr.typ.flags.incl tfNonConstExpr
   result.typ = makeTypeDesc(c, typExpr.typ)
 
 type
@@ -66,7 +70,16 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
   if result.isNil:
     let x = copyTree(n)
     x[0] = newIdentNode(getIdent(c.cache, "[]"), n.info)
-    bracketNotFoundError(c, x)
+    if c.inGenericContext > 0:
+      for i in 0..<n.len:
+        let a = n[i]
+        if a.typ != nil and a.typ.kind in {tyGenericParam, tyFromExpr}:
+          # expression is compiled early in a generic body
+          result = semGenericStmt(c, x)
+          result.typ = makeTypeFromExpr(c, copyTree(result))
+          result.typ.flags.incl tfNonConstExpr
+          return
+    bracketNotFoundError(c, x, flags)
     #localError(c.config, n.info, "could not resolve: " & $n)
     result = errorNode(c, n)
 
@@ -224,8 +237,9 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
   of "rangeBase":
     # return the base type of a range type
     var arg = operand.skipTypes({tyGenericInst})
-    assert arg.kind == tyRange
-    result = getTypeDescNode(c, arg.base, operand.owner, traitCall.info)
+    if arg.kind == tyRange:
+      arg = arg.base
+    result = getTypeDescNode(c, arg, operand.owner, traitCall.info)
   of "isCyclic":
     var operand = operand.skipTypes({tyGenericInst})
     let isCyclic = canFormAcycle(c.graph, operand)
@@ -237,7 +251,7 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
 proc semTypeTraits(c: PContext, n: PNode): PNode =
   checkMinSonsLen(n, 2, c.config)
   let t = n[1].typ
-  internalAssert c.config, t != nil and t.kind == tyTypeDesc
+  internalAssert c.config, t != nil and t.skipTypes({tyAlias}).kind == tyTypeDesc
   if t.len > 0:
     # This is either a type known to sem or a typedesc
     # param to a regular proc (again, known at instantiation)
diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim
index 96b2d702d..048053115 100644
--- a/compiler/semobjconstr.nim
+++ b/compiler/semobjconstr.nim
@@ -387,10 +387,13 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
     if e != nil:
       result.status = initFull
     elif field.ast != nil:
-      result.status = initUnknown
-      result.defaults.add newTree(nkExprColonExpr, n, field.ast)
+      if efIgnoreDefaults notin flags:
+        result.status = initUnknown
+        result.defaults.add newTree(nkExprColonExpr, n, field.ast)
+      else:
+        result.status = initNone
     else:
-      if efWantNoDefaults notin flags: # cannot compute defaults at the typeRightPass
+      if {efWantNoDefaults, efIgnoreDefaults} * flags == {}: # cannot compute defaults at the typeRightPass
         let defaultExpr = defaultNodeField(c, n, constrCtx.checkDefault)
         if defaultExpr != nil:
           result.status = initUnknown
@@ -443,7 +446,7 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
     assert objType != nil
   if objType.kind == tyObject:
     var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
-    let initResult = semConstructTypeAux(c, constrCtx, {efWantNoDefaults})
+    let initResult = semConstructTypeAux(c, constrCtx, {efIgnoreDefaults})
     if constrCtx.missingFields.len > 0:
       localError(c.config, info,
         "The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index f611ee8fe..0a160897f 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -11,7 +11,7 @@ import
   ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
   wordrecg, options, guards, lineinfos, semfold, semdata,
   modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling,
-  semstrictfuncs, suggestsymdb
+  semstrictfuncs, suggestsymdb, pushpoppragmas
 
 import std/[tables, intsets, strutils, sequtils]
 
@@ -85,6 +85,7 @@ type
     isInnerProc: bool
     inEnforcedNoSideEffects: bool
     currOptions: TOptions
+    optionsStack: seq[(TOptions, TNoteKinds)]
     config: ConfigRef
     graph: ModuleGraph
     c: PContext
@@ -615,9 +616,16 @@ proc trackPragmaStmt(tracked: PEffects, n: PNode) =
   for i in 0..<n.len:
     var it = n[i]
     let pragma = whichPragma(it)
-    if pragma == wEffects:
+    case pragma
+    of wEffects:
       # list the computed effects up to here:
       listEffects(tracked)
+    of wPush:
+      processPushBackendOption(tracked.c.config, tracked.optionsStack, tracked.currOptions, n, i+1)
+    of wPop:
+      processPopBackendOption(tracked.c.config, tracked.optionsStack, tracked.currOptions)
+    else:
+      discard
 
 template notGcSafe(t): untyped = {tfGcSafe, tfNoSideEffect} * t.flags == {}
 
@@ -1202,7 +1210,7 @@ proc track(tracked: PEffects, n: PNode) =
     if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
       tracked.owner.flags.incl sfInjectDestructors
       # bug #15038: ensure consistency
-      if not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ): n.typ = n.sym.typ
+      if n.typ == nil or (not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ)): n.typ = n.sym.typ
   of nkHiddenAddr, nkAddr:
     if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym) and
           n.typ.kind notin {tyVar, tyLent}:
@@ -1594,7 +1602,7 @@ proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; c: PContext): TEffects
   result = TEffects(exc: effects[exceptionEffects], tags: effects[tagEffects],
             forbids: effects[forbiddenEffects], owner: s, ownerModule: s.getModule,
             init: @[], locked: @[], graph: g, config: g.config, c: c,
-            currentBlock: 1
+            currentBlock: 1, optionsStack: @[(g.config.options, g.config.notes)]
   )
   result.guards.s = @[]
   result.guards.g = g
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 7ccc29d7e..f5f8fea0c 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -132,17 +132,141 @@ proc semExprBranchScope(c: PContext, n: PNode; expectedType: PType = nil): PNode
   closeScope(c)
 
 const
-  skipForDiscardable = {nkIfStmt, nkIfExpr, nkCaseStmt, nkOfBranch,
-    nkElse, nkStmtListExpr, nkTryStmt, nkFinally, nkExceptBranch,
+  skipForDiscardable = {nkStmtList, nkStmtListExpr,
+    nkOfBranch, nkElse, nkFinally, nkExceptBranch,
     nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt, nkBlockExpr,
-    nkHiddenStdConv, nkHiddenDeref}
+    nkHiddenStdConv, nkHiddenSubConv, nkHiddenDeref}
 
 proc implicitlyDiscardable(n: PNode): bool =
-  var n = n
-  while n.kind in skipForDiscardable: n = n.lastSon
-  result = n.kind in nkLastBlockStmts or
-           (isCallExpr(n) and n[0].kind == nkSym and
-           sfDiscardable in n[0].sym.flags)
+  # same traversal as endsInNoReturn
+  template checkBranch(branch) =
+    if not implicitlyDiscardable(branch):
+      return false
+
+  var it = n
+  # skip these beforehand, no special handling needed
+  while it.kind in skipForDiscardable and it.len > 0:
+    it = it.lastSon
+
+  case it.kind
+  of nkIfExpr, nkIfStmt:
+    for branch in it:
+      checkBranch:
+        if branch.len == 2:
+          branch[1]
+        elif branch.len == 1:
+          branch[0]
+        else:
+          raiseAssert "Malformed `if` statement during implicitlyDiscardable"
+    # all branches are discardable
+    result = true
+  of nkCaseStmt:
+    for i in 1 ..< it.len:
+      let branch = it[i]
+      checkBranch:
+        case branch.kind
+        of nkOfBranch:
+          branch[^1]
+        of nkElifBranch:
+          branch[1]
+        of nkElse:
+          branch[0]
+        else:
+          raiseAssert "Malformed `case` statement in implicitlyDiscardable"
+    # all branches are discardable
+    result = true
+  of nkTryStmt:
+    checkBranch(it[0])
+    for i in 1 ..< it.len:
+      let branch = it[i]
+      if branch.kind != nkFinally:
+        checkBranch(branch[^1])
+    # all branches are discardable
+    result = true
+  of nkCallKinds:
+    result = it[0].kind == nkSym and {sfDiscardable, sfNoReturn} * it[0].sym.flags != {}
+  of nkLastBlockStmts:
+    result = true
+  else:
+    result = false
+
+proc endsInNoReturn(n: PNode, returningNode: var PNode; discardableCheck = false): bool =
+  ## check if expr ends the block like raising or call of noreturn procs do
+  result = false # assume it does return
+
+  template checkBranch(branch) =
+    if not endsInNoReturn(branch, returningNode, discardableCheck):
+      # proved a branch returns
+      return false
+
+  var it = n
+  # skip these beforehand, no special handling needed
+  let skips = if discardableCheck: skipForDiscardable else: skipForDiscardable-{nkBlockExpr, nkBlockStmt}
+  while it.kind in skips and it.len > 0:
+    it = it.lastSon
+
+  case it.kind
+  of nkIfExpr, nkIfStmt:
+    var hasElse = false
+    for branch in it:
+      checkBranch:
+        if branch.len == 2:
+          branch[1]
+        elif branch.len == 1:
+          hasElse = true
+          branch[0]
+        else:
+          raiseAssert "Malformed `if` statement during endsInNoReturn"
+    # none of the branches returned
+    result = hasElse # Only truly a no-return when it's exhaustive
+  of nkCaseStmt:
+    let caseTyp = skipTypes(it[0].typ, abstractVar-{tyTypeDesc})
+    # semCase should already have checked for exhaustiveness in this case
+    # effectively the same as having an else
+    var hasElse = caseTyp.shouldCheckCaseCovered()
+
+    # actual noreturn checks
+    for i in 1 ..< it.len:
+      let branch = it[i]
+      checkBranch:
+        case branch.kind
+        of nkOfBranch:
+          branch[^1]
+        of nkElifBranch:
+          branch[1]
+        of nkElse:
+          hasElse = true
+          branch[0]
+        else:
+          raiseAssert "Malformed `case` statement in endsInNoReturn"
+    # Can only guarantee a noreturn if there is an else or it's exhaustive
+    result = hasElse
+  of nkTryStmt:
+    checkBranch(it[0])
+    var lastIndex = it.len - 1
+    if it[lastIndex].kind == nkFinally:
+      # if finally is noreturn, then the entire statement is noreturn
+      if endsInNoReturn(it[lastIndex][^1], returningNode, discardableCheck):
+        return true
+      dec lastIndex
+    for i in 1 .. lastIndex:
+      let branch = it[i]
+      checkBranch(branch[^1])
+    # none of the branches returned
+    result = true
+  of nkLastBlockStmts:
+    result = true
+  of nkCallKinds:
+    result = it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
+    if not result:
+      returningNode = it
+  else:
+    result = false
+    returningNode = it
+
+proc endsInNoReturn(n: PNode): bool =
+  var dummy: PNode = nil
+  result = endsInNoReturn(n, dummy)
 
 proc fixNilType(c: PContext; n: PNode) =
   if isAtom(n):
@@ -160,18 +284,15 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
     if implicitlyDiscardable(result):
       var n = newNodeI(nkDiscardStmt, result.info, 1)
       n[0] = result
+      # notes that it doesn't transform nodes into discard statements
     elif result.typ.kind != tyError and c.config.cmd != cmdInteractive:
       if result.typ.kind == tyNone:
         localError(c.config, result.info, "expression has no type: " &
                renderTree(result, {renderNoComments}))
       else:
-        var n = result
-        while n.kind in skipForDiscardable:
-          if n.kind == nkTryStmt: n = n[0]
-          else: n = n.lastSon
-
         # Ignore noreturn procs since they don't have a type
-        if n.endsInNoReturn:
+        var n = result
+        if result.endsInNoReturn(n, discardableCheck = true):
           return
 
         var s = "expression '" & $n & "' is of type '" &
@@ -361,7 +482,7 @@ proc identWithin(n: PNode, s: PIdent): bool =
 
 proc semIdentDef(c: PContext, n: PNode, kind: TSymKind, reportToNimsuggest = true): PSym =
   if isTopLevel(c):
-    result = semIdentWithPragma(c, kind, n, {sfExported})
+    result = semIdentWithPragma(c, kind, n, {sfExported}, fromTopLevel = true)
     incl(result.flags, sfGlobal)
     #if kind in {skVar, skLet}:
     #  echo "global variable here ", n.info, " ", result.name.s
@@ -501,15 +622,15 @@ proc setVarType(c: PContext; v: PSym, typ: PType) =
 proc isPossibleMacroPragma(c: PContext, it: PNode, key: PNode): bool =
   # make sure it's not a normal pragma, and calls an identifier
   # considerQuotedIdent below will fail on non-identifiers
-  result = whichPragma(it) == wInvalid and key.kind in nkIdentKinds
+  result = whichPragma(it) == wInvalid and key.kind in nkIdentKinds+{nkDotExpr}
   if result:
     # make sure it's not a user pragma
-    let ident = considerQuotedIdent(c, key)
-    result = strTableGet(c.userPragmas, ident) == nil
+    if key.kind != nkDotExpr:
+      let ident = considerQuotedIdent(c, key)
+      result = strTableGet(c.userPragmas, ident) == nil
     if result:
       # make sure it's not a custom pragma
-      var amb = false
-      let sym = searchInScopes(c, ident, amb)
+      let sym = qualifiedLookUp(c, key, {})
       result = sym == nil or sfCustomPragma notin sym.flags
 
 proc copyExcept(n: PNode, i: int): PNode =
@@ -708,6 +829,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
     var typFlags: TTypeAllowedFlags = {}
 
     var def: PNode = c.graph.emptyNode
+    if typ != nil and typ.kind == tyRange and
+        c.graph.config.isDefined("nimPreviewRangeDefault") and
+        a[^1].kind == nkEmpty:
+      a[^1] = firstRange(c.config, typ)
+
     if a[^1].kind != nkEmpty:
       def = semExprWithType(c, a[^1], {efTypeAllowed}, typ)
 
@@ -859,6 +985,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     var typFlags: TTypeAllowedFlags = {}
 
     # don't evaluate here since the type compatibility check below may add a converter
+    openScope(c)
     var def = semExprWithType(c, a[^1], {efTypeAllowed}, typ)
 
     if def.kind == nkSym and def.sym.kind in {skTemplate, skMacro}:
@@ -885,6 +1012,7 @@ proc semConst(c: PContext, n: PNode): PNode =
       if c.matchedConcept != nil:
         typFlags.incl taConcept
       typeAllowedCheck(c, a.info, typ, skConst, typFlags)
+    closeScope(c)
 
     if a.kind == nkVarTuple:
       # generate new section from tuple unpacking and embed it into this one
@@ -1103,7 +1231,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
   toResolve.add n[0]
 
   var errors: CandidateErrors = @[]
-  var r = resolveOverloads(c, toResolve, toResolve, {skTemplate, skMacro}, {efNoDiagnostics},
+  var r = resolveOverloads(c, toResolve, toResolve, {skTemplate, skMacro}, {efNoUndeclared},
                            errors, false)
   if r.state == csMatch:
     var match = r.calleeSym
@@ -1117,8 +1245,6 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
     of skMacro: result = semMacroExpr(c, toExpand, toExpand, match, flags)
     of skTemplate: result = semTemplateExpr(c, toExpand, match, flags)
     else: result = errorNode(c, n[0])
-  elif r.state == csNoMatch:
-    result = errorNode(c, n[0])
   else:
     result = errorNode(c, n[0])
   if result.kind == nkEmpty:
@@ -1589,21 +1715,27 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
   for sk in c.skipTypes:
     discard semTypeNode(c, sk, nil)
   c.skipTypes = @[]
-proc checkForMetaFields(c: PContext; n: PNode) =
-  proc checkMeta(c: PContext; n: PNode; t: PType) =
-    if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
+
+proc checkForMetaFields(c: PContext; n: PNode; hasError: var bool) =
+  proc checkMeta(c: PContext; n: PNode; t: PType; hasError: var bool; parent: PType) =
+    if t != nil and (t.isMetaType or t.kind == tyNone) and tfGenericTypeParam notin t.flags:
       if t.kind == tyBuiltInTypeClass and t.len == 1 and t.elementType.kind == tyProc:
         localError(c.config, n.info, ("'$1' is not a concrete type; " &
           "for a callback without parameters use 'proc()'") % t.typeToString)
+      elif t.kind == tyNone and parent != nil:
+        # TODO: openarray has the `tfGenericTypeParam` flag & generics
+        # TODO: handle special cases (sink etc.) and views
+        localError(c.config, n.info, errTIsNotAConcreteType % parent.typeToString)
       else:
         localError(c.config, n.info, errTIsNotAConcreteType % t.typeToString)
+      hasError = true
 
   if n.isNil: return
   case n.kind
   of nkRecList, nkRecCase:
-    for s in n: checkForMetaFields(c, s)
+    for s in n: checkForMetaFields(c, s, hasError)
   of nkOfBranch, nkElse:
-    checkForMetaFields(c, n.lastSon)
+    checkForMetaFields(c, n.lastSon, hasError)
   of nkSym:
     let t = n.sym.typ
     case t.kind
@@ -1611,9 +1743,9 @@ proc checkForMetaFields(c: PContext; n: PNode) =
        tyProc, tyGenericInvocation, tyGenericInst, tyAlias, tySink, tyOwned:
       let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
       for i in start..<t.len:
-        checkMeta(c, n, t[i])
+        checkMeta(c, n, t[i], hasError, t)
     else:
-      checkMeta(c, n, t)
+      checkMeta(c, n, t, hasError, nil)
   else:
     internalAssert c.config, false
 
@@ -1648,13 +1780,16 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
               assert s.typ != nil
               assignType(s.typ, t)
               s.typ.itemId = t.itemId     # same id
-        checkConstructedType(c.config, s.info, s.typ)
-        if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
-          checkForMetaFields(c, s.typ.n)
-
-        # fix bug #5170, bug #17162, bug #15526: ensure locally scoped types get a unique name:
-        if s.typ.kind in {tyEnum, tyRef, tyObject} and not isTopLevel(c):
-          incl(s.flags, sfGenSym)
+        var hasError = false
+        let baseType = s.typ.safeSkipTypes(abstractPtrs)
+        if baseType.kind in {tyObject, tyTuple} and not baseType.n.isNil and
+          (x.kind in {nkObjectTy, nkTupleTy} or
+           (x.kind in {nkRefTy, nkPtrTy} and x.len == 1 and
+           x[0].kind in {nkObjectTy, nkTupleTy})
+          ):
+          checkForMetaFields(c, baseType.n, hasError)
+        if not hasError:
+          checkConstructedType(c.config, s.info, s.typ)
   #instAllTypeBoundOp(c, n.info)
 
 
@@ -2600,20 +2735,23 @@ proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) =
 proc evalInclude(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   result.add n
+  template checkAs(it: PNode) =
+    if it.kind == nkInfix and it.len == 3:
+      let op = it[0].getPIdent
+      if op != nil and op.id == ord(wAs):
+        localError(c.config, it.info, "Cannot use '" & it[0].renderTree & "' in 'include'.")
   for i in 0..<n.len:
-    var imp: PNode
     let it = n[i]
-    if it.kind == nkInfix and it.len == 3 and it[0].ident.s != "/":
-      localError(c.config, it.info, "Cannot use '" & it[0].ident.s & "' in 'include'.")
-    if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
-      let sep = it[0]
-      let dir = it[1]
-      imp = newNodeI(nkInfix, it.info)
-      imp.add sep
-      imp.add dir
-      imp.add sep # dummy entry, replaced in the loop
-      for x in it[2]:
-        imp[2] = x
+    checkAs(it)
+    if it.kind in {nkInfix, nkPrefix} and it[^1].kind == nkBracket:
+      let lastPos = it.len - 1
+      var imp = copyNode(it)
+      newSons(imp, it.len)
+      for i in 0 ..< lastPos: imp[i] = it[i]
+      imp[lastPos] = imp[0] # dummy entry, replaced in the loop
+      for x in it[lastPos]:
+        checkAs(x)
+        imp[lastPos] = x
         incMod(c, n, imp, result)
     else:
       incMod(c, n, it, result)
@@ -2724,7 +2862,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType =
         let verdict = semConstExpr(c, n[i])
         if verdict == nil or verdict.kind != nkIntLit or verdict.intVal == 0:
           localError(c.config, result.info, "concept predicate failed")
-      of tyUnknown: continue
+      of tyFromExpr: continue
       else: discard
     if n[i].typ == c.enforceVoidContext: #or usesResult(n[i]):
       voidContext = true
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index f2083c85c..817cb6249 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -218,63 +218,98 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
         if k == skParam and c.inTemplateHeader > 0:
           local.flags.incl sfTemplateParam
 
-proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
+proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bool): PNode =
   incl(s.flags, sfUsed)
   # bug #12885; ideally sem'checking is performed again afterwards marking
   # the symbol as used properly, but the nfSem mechanism currently prevents
   # that from happening, so we mark the module as used here already:
-  markOwnerModuleAsUsed(c, s)
+  markOwnerModuleAsUsed(c.c, s)
   # 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:
     # Introduced in this pass! Leave it as an identifier.
     result = n
-  of OverloadableSyms-{skTemplate,skMacro}:
-    result = symChoice(c, n, s, scOpen, isField)
-  of skTemplate, skMacro:
-    result = symChoice(c, n, s, scOpen, isField)
-    if result.kind == nkSym:
-      # template/macro symbols might need to be semchecked again
-      # prepareOperand etc don't do this without setting the type to nil
-      result.typ = nil
+  of OverloadableSyms:
+    result = symChoice(c.c, n, s, scOpen, isField)
+    if not isField and result.kind in {nkSym, nkOpenSymChoice}:
+      if openSym in c.c.features:
+        if result.kind == nkSym:
+          result = newOpenSym(result)
+        else:
+          result.typ = nil
+      else:
+        result.flags.incl nfDisabledOpenSym
+        result.typ = nil
   of skGenericParam:
     if isField and sfGenSym in s.flags: result = n
-    else: result = newSymNodeTypeDesc(s, c.idgen, n.info)
+    else:
+      result = newSymNodeTypeDesc(s, c.c.idgen, n.info)
+      if not isField and s.owner != c.owner:
+        if openSym in c.c.features:
+          result = newOpenSym(result)
+        else:
+          result.flags.incl nfDisabledOpenSym
+          result.typ = nil
   of skParam:
     result = n
   of skType:
     if isField and sfGenSym in s.flags: result = n
-    else: result = newSymNodeTypeDesc(s, c.idgen, n.info)
+    else:
+      if isAmbiguous:
+        # ambiguous types should be symchoices since lookup behaves
+        # differently for them in regular expressions
+        result = symChoice(c.c, n, s, scOpen, isField)
+      else: result = newSymNodeTypeDesc(s, c.c.idgen, n.info)
+      if not isField and not (s.owner == c.owner and
+          s.typ != nil and s.typ.kind == tyGenericParam) and
+          result.kind in {nkSym, nkOpenSymChoice}:
+        if openSym in c.c.features:
+          if result.kind == nkSym:
+            result = newOpenSym(result)
+          else:
+            result.typ = nil
+        else:
+          result.flags.incl nfDisabledOpenSym
+          result.typ = nil
   else:
     if isField and sfGenSym in s.flags: result = n
-    else: result = newSymNode(s, n.info)
+    else:
+      result = newSymNode(s, n.info)
+      if not isField:
+        if openSym in c.c.features:
+          result = newOpenSym(result)
+        else:
+          result.flags.incl nfDisabledOpenSym
+          result.typ = nil
     # Issue #12832
     when defined(nimsuggest):
-      suggestSym(c.graph, n.info, s, c.graph.usageSym, false)
+      suggestSym(c.c.graph, n.info, s, c.c.graph.usageSym, false)
     # field access (dot expr) will be handled by builtinFieldAccess
     if not isField:
-      styleCheckUse(c, n.info, s)
+      styleCheckUse(c.c, n.info, s)
 
-proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
+proc semRoutineInTemplName(c: var TemplCtx, n: PNode, explicitInject: bool): PNode =
   result = n
   if n.kind == nkIdent:
     let s = qualifiedLookUp(c.c, n, {})
     if s != nil:
-      if s.owner == c.owner and s.kind == skParam:
+      if s.owner == c.owner and (s.kind == skParam or
+          (sfGenSym in s.flags and not explicitInject)):
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
         onUse(n.info, s)
   else:
     for i in 0..<n.safeLen:
-      result[i] = semRoutineInTemplName(c, n[i])
+      result[i] = semRoutineInTemplName(c, n[i], explicitInject)
 
 proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
   result = n
   checkSonsLen(n, bodyPos + 1, c.c.config)
   if n.kind notin nkLambdaKinds:
     # routines default to 'inject':
-    if symBinding(n[pragmasPos]) == spGenSym:
+    let binding = symBinding(n[pragmasPos])
+    if binding == spGenSym:
       let (ident, hasParam) = getIdentReplaceParams(c, n[namePos])
       if not hasParam:
         var s = newGenSym(k, ident, c)
@@ -286,7 +321,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
       else:
         n[namePos] = ident
     else:
-      n[namePos] = semRoutineInTemplName(c, n[namePos])
+      n[namePos] = semRoutineInTemplName(c, n[namePos], binding == spInject)
   # open scope for parameters
   openScope(c)
   for i in patternPos..paramsPos-1:
@@ -343,6 +378,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   case n.kind
   of nkIdent:
     if n.ident.id in c.toInject: return n
+    c.c.isAmbiguous = false
     let s = qualifiedLookUp(c.c, n, {})
     if s != nil:
       if s.owner == c.owner and s.kind == skParam and sfTemplateParam in s.flags:
@@ -360,9 +396,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         result = newSymNode(s, n.info)
         onUse(n.info, s)
       else:
-        if s.kind in {skType, skVar, skLet, skConst}:
+        if s.kind in {skVar, skLet, skConst}:
           discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
-        result = semTemplSymbol(c.c, n, s, c.noGenSym > 0)
+        result = semTemplSymbol(c, n, s, c.noGenSym > 0, c.c.isAmbiguous)
   of nkBind:
     result = semTemplBody(c, n[0])
   of nkBindStmt:
@@ -556,6 +592,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   of nkDotExpr, nkAccQuoted:
     # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
     # so we use the generic code for nkDotExpr too
+    c.c.isAmbiguous = false
     let s = qualifiedLookUp(c.c, n, {})
     if s != nil:
       # mirror the nkIdent case
@@ -570,9 +607,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
       elif contains(c.toMixin, s.name.id):
         return symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
       else:
-        if s.kind in {skType, skVar, skLet, skConst}:
+        if s.kind in {skVar, skLet, skConst}:
           discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
-        return semTemplSymbol(c.c, n, s, c.noGenSym > 0)
+        return semTemplSymbol(c, n, s, c.noGenSym > 0, c.c.isAmbiguous)
     if n.kind == nkDotExpr:
       result = n
       result[0] = semTemplBody(c, n[0])
@@ -656,6 +693,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   pushOwner(c, s)
   openScope(c)
   n[namePos] = newSymNode(s)
+  s.ast = n # for implicitPragmas to use
   pragmaCallable(c, s, n, templatePragmas)
   implicitPragmas(c, s, n.info, templatePragmas)
 
@@ -706,6 +744,17 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
     c: c,
     owner: s
   )
+  # handle default params:
+  for i in 1..<s.typ.n.len:
+    let param = s.typ.n[i].sym
+    if param.ast != nil:
+      # param default values need to be treated like template body:
+      if sfDirty in s.flags:
+        param.ast = semTemplBodyDirty(ctx, param.ast)
+      else:
+        param.ast = semTemplBody(ctx, param.ast)
+      if param.ast.referencesAnotherParam(s):
+        param.ast.flags.incl nfDefaultRefsParam
   if sfDirty in s.flags:
     n[bodyPos] = semTemplBodyDirty(ctx, n[bodyPos])
   else:
@@ -715,11 +764,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   closeScope(c)
   popOwner(c)
 
-  # set the symbol AST after pragmas, at least. This stops pragma that have
-  # been pushed (implicit) to be explicitly added to the template definition
-  # and misapplied to the body. see #18113
-  s.ast = n
-
   if sfCustomPragma in s.flags:
     if n[bodyPos].kind != nkEmpty:
       localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index c88795517..113946fef 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -15,7 +15,7 @@ const
   errStringLiteralExpected = "string literal expected"
   errIntLiteralExpected = "integer literal expected"
   errWrongNumberOfVariables = "wrong number of variables"
-  errInvalidOrderInEnumX = "invalid order in enum '$1'"
+  errDuplicateAliasInEnumX = "duplicate value in enum '$1'"
   errOverflowInEnumX = "The enum '$1' exceeds its maximum value ($2)"
   errOrdinalTypeExpected = "ordinal type expected; given: $1"
   errSetTooBig = "set is too large; use `std/sets` for ordinal types with more than 2^16 elements"
@@ -69,6 +69,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
     e: PSym = nil
     base: PType = nil
     identToReplace: ptr PNode = nil
+    counterSet = initPackedSet[BiggestInt]()
   counter = 0
   base = nil
   result = newOrPrevType(tyEnum, prev, c)
@@ -85,6 +86,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
   var hasNull = false
   for i in 1..<n.len:
     if n[i].kind == nkEmpty: continue
+    var useAutoCounter = false
     case n[i].kind
     of nkEnumFieldDef:
       if n[i][0].kind == nkPragmaExpr:
@@ -112,6 +114,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       of tyString, tyCstring:
         strVal = v
         x = counter
+        useAutoCounter = true
       else:
         if isOrdinalType(v.typ, allowEnumWithHoles=true):
           x = toInt64(getOrdValue(v))
@@ -120,22 +123,30 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
           localError(c.config, v.info, errOrdinalTypeExpected % typeToString(v.typ, preferDesc))
       if i != 1:
         if x != counter: incl(result.flags, tfEnumHasHoles)
-        if x < counter:
-          localError(c.config, n[i].info, errInvalidOrderInEnumX % e.name.s)
-          x = counter
       e.ast = strVal # might be nil
       counter = x
     of nkSym:
       e = n[i].sym
+      useAutoCounter = true
     of nkIdent, nkAccQuoted:
       e = newSymS(skEnumField, n[i], c)
       identToReplace = addr n[i]
+      useAutoCounter = true
     of nkPragmaExpr:
       e = newSymS(skEnumField, n[i][0], c)
       pragma(c, e, n[i][1], enumFieldPragmas)
       identToReplace = addr n[i][0]
+      useAutoCounter = true
     else:
       illFormedAst(n[i], c.config)
+
+    if useAutoCounter:
+      while counter in counterSet and counter != high(typeof(counter)):
+        inc counter
+      counterSet.incl counter
+    elif counterSet.containsOrIncl(counter):
+      localError(c.config, n[i].info, errDuplicateAliasInEnumX % e.name.s)
+
     e.typ = result
     e.position = int(counter)
     let symNode = newSymNode(e)
@@ -464,6 +475,13 @@ proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
     let t = semTypeNode(c, it, nil)
     addSonSkipIntLitChecked(c, result, t, it, c.idgen)
 
+proc firstRange(config: ConfigRef, t: PType): PNode =
+  if t.skipModifier().kind in tyFloat..tyFloat64:
+    result = newFloatNode(nkFloatLit, firstFloat(t))
+  else:
+    result = newIntNode(nkIntLit, firstOrd(config, t))
+  result.typ = t
+
 proc semTuple(c: PContext, n: PNode, prev: PType): PType =
   var typ: PType
   result = newOrPrevType(tyTuple, prev, c)
@@ -480,8 +498,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
     elif a[^2].kind != nkEmpty:
       typ = semTypeNode(c, a[^2], nil)
       if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
-        a[^1] = newIntNode(nkIntLit, firstOrd(c.config, typ))
-        a[^1].typ = typ
+        a[^1] = firstRange(c.config, typ)
         hasDefaultField = true
     else:
       localError(c.config, a.info, errTypeExpected)
@@ -529,7 +546,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
     result = newSymG(kind, n, c)
 
 proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
-                        allowed: TSymFlags): PSym =
+                        allowed: TSymFlags, fromTopLevel = false): PSym =
   if n.kind == nkPragmaExpr:
     checkSonsLen(n, 2, c.config)
     result = semIdentVis(c, kind, n[0], allowed)
@@ -544,11 +561,15 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
     else: discard
   else:
     result = semIdentVis(c, kind, n, allowed)
+    let invalidPragmasForPush = if fromTopLevel and sfWasGenSym notin result.flags:
+      {}
+    else:
+      {wExportc, wExportCpp, wDynlib}
     case kind
     of skField: implicitPragmas(c, result, n.info, fieldPragmas)
-    of skVar:   implicitPragmas(c, result, n.info, varPragmas)
-    of skLet:   implicitPragmas(c, result, n.info, letPragmas)
-    of skConst: implicitPragmas(c, result, n.info, constPragmas)
+    of skVar:   implicitPragmas(c, result, n.info, varPragmas-invalidPragmasForPush)
+    of skLet:   implicitPragmas(c, result, n.info, letPragmas-invalidPragmasForPush)
+    of skConst: implicitPragmas(c, result, n.info, constPragmas-invalidPragmasForPush)
     else: discard
 
 proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
@@ -565,9 +586,14 @@ proc semBranchRange(c: PContext, n, a, b: PNode, covered: var Int128): PNode =
   let bc = semConstExpr(c, b)
   if ac.kind in {nkStrLit..nkTripleStrLit} or bc.kind in {nkStrLit..nkTripleStrLit}:
     localError(c.config, b.info, "range of string is invalid")
-  let at = fitNode(c, n[0].typ, ac, ac.info).skipConvTakeType
-  let bt = fitNode(c, n[0].typ, bc, bc.info).skipConvTakeType
-
+  var at = fitNode(c, n[0].typ, ac, ac.info).skipConvTakeType
+  var bt = fitNode(c, n[0].typ, bc, bc.info).skipConvTakeType
+  # the calls to fitNode may introduce calls to converters
+  # mirrored with semCaseBranch for single elements
+  if at.kind in {nkHiddenCallConv, nkHiddenStdConv, nkHiddenSubConv}:
+    at = semConstExpr(c, at)
+  if bt.kind in {nkHiddenCallConv, nkHiddenStdConv, nkHiddenSubConv}:
+    bt = semConstExpr(c, bt)
   result = newNodeI(nkRange, a.info)
   result.add(at)
   result.add(bt)
@@ -598,6 +624,8 @@ proc semCaseBranch(c: PContext, n, branch: PNode, branchIndex: int,
     var b = branch[i]
     if b.kind == nkRange:
       branch[i] = b
+      # same check as in semBranchRange for exhaustiveness
+      covered = covered + getOrdValue(b[1]) + 1 - getOrdValue(b[0])
     elif isRange(b):
       branch[i] = semCaseBranchRange(c, n, b, covered)
     else:
@@ -613,8 +641,8 @@ proc semCaseBranch(c: PContext, n, branch: PNode, branchIndex: int,
         checkMinSonsLen(n, 1, c.config)
         var tmp = fitNode(c, n[0].typ, r, r.info)
         # the call to fitNode may introduce a call to a converter
-        if tmp.kind == nkHiddenCallConv or
-            (tmp.kind == nkHiddenStdConv and n[0].typ.kind == tyCstring):
+        # mirrored with semBranchRange
+        if tmp.kind in {nkHiddenCallConv, nkHiddenStdConv, nkHiddenSubConv}:
           tmp = semConstExpr(c, tmp)
         branch[i] = skipConv(tmp)
         inc(covered)
@@ -768,6 +796,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
   of nkRecWhen:
     var a = copyTree(n)
     var branch: PNode = nil   # the branch to take
+    var cannotResolve = false # no branch should be taken
     for i in 0..<a.len:
       var it = a[i]
       if it == nil: illFormedAst(n, c.config)
@@ -785,24 +814,30 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
           let e = semExprWithType(c, it[0], {efDetermineType})
           if e.typ.kind == tyFromExpr:
             it[0] = makeStaticExpr(c, e)
+            cannotResolve = true
           else:
             it[0] = forceBool(c, e)
+            let val = getConstExpr(c.module, it[0], c.idgen, c.graph)
+            if val == nil or val.kind != nkIntLit:
+              cannotResolve = true
+            elif not cannotResolve and val.intVal != 0 and branch == nil:
+              branch = it[1]
       of nkElse:
         checkSonsLen(it, 1, c.config)
-        if branch == nil: branch = it[0]
+        if branch == nil and not cannotResolve: branch = it[0]
         idx = 0
       else: illFormedAst(n, c.config)
-      if c.inGenericContext > 0:
+      if c.inGenericContext > 0 and cannotResolve:
         # use a new check intset here for each branch:
         var newCheck: IntSet = check
         var newPos = pos
         var newf = newNodeI(nkRecList, n.info)
         semRecordNodeAux(c, it[idx], newCheck, newPos, newf, rectype, hasCaseFields)
         it[idx] = if newf.len == 1: newf[0] else: newf
-    if c.inGenericContext > 0:
-      father.add a
-    elif branch != nil:
+    if branch != nil:
       semRecordNodeAux(c, branch, check, pos, father, rectype, hasCaseFields)
+    elif cannotResolve:
+      father.add a
     elif father.kind in {nkElse, nkOfBranch}:
       father.add newNodeI(nkRecList, n.info)
   of nkRecCase:
@@ -831,8 +866,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
     else:
       typ = semTypeNode(c, n[^2], nil)
       if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
-        n[^1] = newIntNode(nkIntLit, firstOrd(c.config, typ))
-        n[^1].typ = typ
+        n[^1] = firstRange(c.config, typ)
         hasDefaultField = true
       propagateToOwner(rectype, typ)
     var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner
@@ -849,8 +883,8 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
       f.options = c.config.options
       if fieldOwner != nil and
          {sfImportc, sfExportc} * fieldOwner.flags != {} and
-         not hasCaseFields and f.loc.r == "":
-        f.loc.r = rope(f.name.s)
+         not hasCaseFields and f.loc.snippet == "":
+        f.loc.snippet = rope(f.name.s)
         f.flags.incl {sfImportc, sfExportc} * fieldOwner.flags
       inc(pos)
       if containsOrIncl(check, f.name.id):
@@ -1151,11 +1185,11 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
         paramType[i] = t
         result = paramType
 
-  of tyAlias, tyOwned, tySink:
+  of tyAlias, tyOwned:
     result = recurse(paramType.base)
 
   of tySequence, tySet, tyArray, tyOpenArray,
-     tyVar, tyLent, tyPtr, tyRef, tyProc:
+     tyVar, tyLent, tyPtr, tyRef, tyProc, tySink:
     # XXX: this is a bit strange, but proc(s: seq)
     # produces tySequence(tyGenericParam, tyNone).
     # This also seems to be true when creating aliases
@@ -1262,7 +1296,7 @@ proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
     result = semTypeNode(c, n[0], nil)
     constraint = semNodeKindConstraints(n, c.config, 1)
   elif n.kind == nkCall and
-      n[0].kind in {nkIdent, nkSym, nkOpenSymChoice, nkClosedSymChoice} and
+      n[0].kind in {nkIdent, nkSym, nkOpenSymChoice, nkClosedSymChoice, nkOpenSym} and
       considerQuotedIdent(c, n[0]).s == "{}":
     result = semTypeNode(c, n[1], nil)
     constraint = semNodeKindConstraints(n, c.config, 2)
@@ -1292,6 +1326,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
   result = newProcType(c, n.info, prev)
   var check = initIntSet()
   var counter = 0
+  template isCurrentlyGeneric: bool =
+    # genericParams might update as implicit generic params are added
+    genericParams != nil and genericParams.len > 0
 
   for i in 1..<n.len:
     var a = n[i]
@@ -1312,7 +1349,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       hasDefault = a[^1].kind != nkEmpty
 
     if hasType:
+      let isGeneric = isCurrentlyGeneric()
+      inc c.inGenericContext, ord(isGeneric)
       typ = semParamType(c, a[^2], constraint)
+      dec c.inGenericContext, ord(isGeneric)
       # TODO: Disallow typed/untyped in procs in the compiler/stdlib
       if kind in {skProc, skFunc} and (typ.kind == tyTyped or typ.kind == tyUntyped):
         if not isMagic(getCurrOwner(c)):
@@ -1332,15 +1372,26 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
           "either use ';' (semicolon) or explicitly write each default value")
         message(c.config, a.info, warnImplicitDefaultValue, msg)
       block determineType:
-        var defTyp = typ
-        if genericParams != nil and genericParams.len > 0:
-          defTyp = nil
-          def = semGenericStmt(c, def)
-          if hasUnresolvedArgs(c, def):
+        var canBeVoid = false
+        if kind == skTemplate:
+          if typ != nil and typ.kind == tyUntyped:
+            # don't do any typechecking or assign a type for
+            # `untyped` parameter default value
+            break determineType
+          elif hasUnresolvedArgs(c, def):
+            # template default value depends on other parameter
+            # don't do any typechecking
             def.typ = makeTypeFromExpr(c, def.copyTree)
             break determineType
-
-        def = semExprWithType(c, def, {efDetermineType, efAllowSymChoice}, defTyp)
+          elif typ != nil and typ.kind == tyTyped:
+            canBeVoid = true
+        let isGeneric = isCurrentlyGeneric()
+        inc c.inGenericContext, ord(isGeneric)
+        if canBeVoid:
+          def = semExpr(c, def, {efDetermineType, efAllowSymChoice}, typ)
+        else:
+          def = semExprWithType(c, def, {efDetermineType, efAllowSymChoice}, typ)
+        dec c.inGenericContext, ord(isGeneric)
         if def.referencesAnotherParam(getCurrOwner(c)):
           def.flags.incl nfDefaultRefsParam
 
@@ -1359,7 +1410,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
           typ = newTypeS(tyTypeDesc, c, newTypeS(tyNone, c))
           typ.flags.incl tfCheckedForDestructor
 
-      else:
+      elif def.typ != nil and def.typ.kind != tyFromExpr: # def.typ can be void
         # if def.typ != nil and def.typ.kind != tyNone:
         # example code that triggers it:
         # proc sort[T](cmp: proc(a, b: T): int = cmp)
@@ -1412,11 +1463,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       onDef(a[j].info, arg)
       a[j] = newSymNode(arg)
 
-  var r: PType =
-    if n[0].kind != nkEmpty:
-      semTypeNode(c, n[0], nil)
-    else:
-      nil
+  var r: PType = nil
+  if n[0].kind != nkEmpty:
+    let isGeneric = isCurrentlyGeneric()
+    inc c.inGenericContext, ord(isGeneric)
+    r = semTypeNode(c, n[0], nil)
+    dec c.inGenericContext, ord(isGeneric)
 
   if r != nil and kind in {skMacro, skTemplate} and r.kind == tyTyped:
     # XXX: To implement the proposed change in the warning, just
@@ -1469,7 +1521,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
           result.flags.excl tfHasMeta
       result.n.typ = r
 
-  if genericParams != nil and genericParams.len > 0:
+  if isCurrentlyGeneric():
     for n in genericParams:
       if {sfUsed, sfAnon} * n.sym.flags == {}:
         result.flags.incl tfUnresolved
@@ -1626,7 +1678,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     recomputeFieldPositions(tx, tx.n, position)
 
 proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
-  if typeExpr.kind in {tyObject, tyEnum, tyDistinct, tyForward, tyGenericBody} and prev != nil:
+  if prev != nil and (prev.kind == tyGenericBody or
+      typeExpr.kind in {tyObject, tyEnum, tyDistinct, tyForward, tyGenericBody}):
     result = newTypeS(tyAlias, c)
     result.rawAddSon typeExpr
     result.sym = prev.sym
@@ -1664,6 +1717,10 @@ proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
         # unnecessary new type creation
         let alias = maybeAliasType(c, result, prev)
         if alias != nil: result = alias
+  elif n.typ.kind == tyFromExpr and c.inGenericContext > 0:
+    # sometimes not possible to distinguish type from value in generic body,
+    # for example `T.Foo`, so both are handled under `tyFromExpr`
+    result = n.typ
   else:
     localError(c.config, n.info, "expected type, but got: " & n.renderTree)
     result = errorType(c)
@@ -1749,12 +1806,15 @@ proc applyTypeSectionPragmas(c: PContext; pragmas, operand: PNode): PNode =
       discard "builtin pragma"
     else:
       trySuggestPragmas(c, key)
-      let ident = considerQuotedIdent(c, key)
-      if strTableGet(c.userPragmas, ident) != nil:
+      let ident =
+        if key.kind in nkIdentKinds:
+          considerQuotedIdent(c, key)
+        else:
+          nil
+      if ident != nil and strTableGet(c.userPragmas, ident) != nil:
         discard "User-defined pragma"
       else:
-        var amb = false
-        let sym = searchInScopes(c, ident, amb)
+        let sym = qualifiedLookUp(c, key, {})
         # XXX: What to do here if amb is true?
         if sym != nil and sfCustomPragma in sym.flags:
           discard "Custom user pragma"
@@ -1821,10 +1881,14 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =
 
 proc semTypeOf(c: PContext; n: PNode; prev: PType): PType =
   openScope(c)
+  inc c.inTypeofContext
+  defer: dec c.inTypeofContext # compiles can raise an exception
   let t = semExprWithType(c, n, {efInTypeof})
   closeScope(c)
   fixupTypeOf(c, prev, t)
   result = t.typ
+  if result.kind == tyFromExpr:
+    result.flags.incl tfNonConstExpr
 
 proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
   openScope(c)
@@ -1835,10 +1899,14 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
       localError(c.config, n.info, "typeof: cannot evaluate 'mode' parameter at compile-time")
     else:
       m = mode.intVal
+  inc c.inTypeofContext
+  defer: dec c.inTypeofContext # compiles can raise an exception
   let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
   closeScope(c)
   fixupTypeOf(c, prev, t)
   result = t.typ
+  if result.kind == tyFromExpr:
+    result.flags.incl tfNonConstExpr
 
 proc semTypeIdent(c: PContext, n: PNode): PSym =
   if n.kind == nkSym:
@@ -1926,11 +1994,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkTupleConstr: result = semAnonTuple(c, n, prev)
   of nkCallKinds:
     let x = n[0]
-    let ident = case x.kind
-                of nkIdent: x.ident
-                of nkSym: x.sym.name
-                of nkClosedSymChoice, nkOpenSymChoice: x[0].sym.name
-                else: nil
+    let ident = x.getPIdent
     if ident != nil and ident.s == "[]":
       let b = newNodeI(nkBracketExpr, n.info)
       for i in 1..<n.len: b.add(n[i])
@@ -2020,20 +2084,21 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       elif op.id == ord(wType):
         checkSonsLen(n, 2, c.config)
         result = semTypeOf(c, n[1], prev)
-      elif op.s == "typeof" and n[0].kind == nkSym and n[0].sym.magic == mTypeOf:
+      elif op.s == "typeof" and (
+          (n[0].kind == nkSym and n[0].sym.magic == mTypeOf) or
+          (n[0].kind == nkOpenSym and n[0][0].sym.magic == mTypeOf)):
         result = semTypeOf2(c, n, prev)
       elif op.s == "owned" and optOwnedRefs notin c.config.globalOptions and n.len == 2:
         result = semTypeExpr(c, n[1], prev)
       else:
-        if c.inGenericContext > 0 and n.kind == nkCall:
-          let n = semGenericStmt(c, n)
-          result = makeTypeFromExpr(c, n.copyTree)
-        else:
-          result = semTypeExpr(c, n, prev)
+        result = semTypeExpr(c, n, prev)
   of nkWhenStmt:
     var whenResult = semWhen(c, n, false)
     if whenResult.kind == nkStmtList: whenResult.transitionSonsKind(nkStmtListType)
-    result = semTypeNode(c, whenResult, prev)
+    if whenResult.kind == nkWhenStmt:
+      result = whenResult.typ
+    else:
+      result = semTypeNode(c, whenResult, prev)
   of nkBracketExpr:
     checkMinSonsLen(n, 2, c.config)
     var head = n[0]
@@ -2078,6 +2143,12 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     of mRef: result = semAnyRef(c, n, tyRef, prev)
     of mPtr: result = semAnyRef(c, n, tyPtr, prev)
     of mTuple: result = semTuple(c, n, prev)
+    of mBuiltinType:
+      case s.name.s
+      of "lent": result = semAnyRef(c, n, tyLent, prev)
+      of "sink": result = semAnyRef(c, n, tySink, prev)
+      of "owned": result = semAnyRef(c, n, tyOwned, prev)
+      else: result = semGeneric(c, n, s, prev)
     else: result = semGeneric(c, n, s, prev)
   of nkDotExpr:
     let typeExpr = semExpr(c, n)
@@ -2107,7 +2178,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       if s.kind != skError: localError(c.config, n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
     elif s.kind == skParam and s.typ.kind == tyTypeDesc:
-      internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
+      internalAssert c.config, s.typ.base.kind != tyNone
       result = s.typ.base
     elif prev == nil:
       result = s.typ
@@ -2131,7 +2202,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         if s.kind == skType:
           s.typ
         else:
-          internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
+          internalAssert c.config, s.typ.base.kind != tyNone
           s.typ.base
       let alias = maybeAliasType(c, t, prev)
       if alias != nil:
@@ -2192,6 +2263,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkType: result = n.typ
   of nkStmtListType: result = semStmtListType(c, n, prev)
   of nkBlockType: result = semBlockType(c, n, prev)
+  of nkOpenSym: result = semTypeNode(c, n[0], prev)
   else:
     result = semTypeExpr(c, n, prev)
     when false:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index f0ce8d76f..759e8e6ab 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -118,7 +118,12 @@ proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
   result = replaceTypeVarsTAux(cl, t)
   checkMetaInvariants(cl, result)
 
-proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
+proc prepareNode*(cl: var TReplTypeVars, n: PNode): PNode =
+  ## instantiates a given generic expression, not a type node
+  if n.kind == nkSym and n.sym.kind == skType and
+      n.sym.typ != nil and n.sym.typ.kind == tyGenericBody:
+    # generic body types are allowed as user expressions, see #24090
+    return n
   let t = replaceTypeVarsT(cl, n.typ)
   if t != nil and t.kind == tyStatic and t.n != nil:
     return if tfUnresolved in t.flags: prepareNode(cl, t.n)
@@ -131,11 +136,68 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
         replaceTypeVarsS(cl, n.sym, result.typ)
       else:
         replaceTypeVarsS(cl, n.sym, replaceTypeVarsT(cl, n.sym.typ))
-  let isCall = result.kind in nkCallKinds
-  for i in 0..<n.safeLen:
-    # XXX HACK: ``f(a, b)``, avoid to instantiate `f`
-    if isCall and i == 0: result.add(n[i])
-    else: result.add(prepareNode(cl, n[i]))
+  # we need to avoid trying to instantiate nodes that can have uninstantiated
+  # types, like generic proc symbols or raw generic type symbols
+  case n.kind
+  of nkSymChoices:
+    # don't try to instantiate symchoice symbols, they can be
+    # generic procs which the compiler will think are uninstantiated
+    # because their type will contain uninstantiated params
+    for i in 0..<n.len:
+      result.add(n[i])
+  of nkCallKinds:
+    # don't try to instantiate call names since they may be generic proc syms
+    # also bracket expressions can turn into calls with symchoice [] and
+    # we need to not instantiate the Generic in Generic[int]
+    # exception exists for the call name being a dot expression since
+    # dot expressions need their LHS instantiated
+    assert n.len != 0
+    # avoid instantiating generic proc symbols, refine condition if needed:
+    let ignoreFirst = n[0].kind notin {nkDotExpr, nkBracketExpr} + nkCallKinds
+    let name = n[0].getPIdent
+    let ignoreSecond = name != nil and name.s == "[]" and n.len > 1 and
+      # generic type instantiation:
+      ((n[1].typ != nil and n[1].typ.kind == tyTypeDesc) or
+        # generic proc instantiation:
+        (n[1].kind == nkSym and n[1].sym.isGenericRoutineStrict))
+    if ignoreFirst:
+      result.add(n[0])
+    else:
+      result.add(prepareNode(cl, n[0]))
+    if n.len > 1:
+      if ignoreSecond:
+        result.add(n[1])
+      else:
+        result.add(prepareNode(cl, n[1]))
+    for i in 2..<n.len:
+      result.add(prepareNode(cl, n[i]))
+  of nkBracketExpr:
+    # don't instantiate Generic body type in expression like Generic[T]
+    # exception exists for the call name being a dot expression since
+    # dot expressions need their LHS instantiated
+    assert n.len != 0
+    let ignoreFirst = n[0].kind != nkDotExpr and
+      # generic type instantiation:
+      ((n[0].typ != nil and n[0].typ.kind == tyTypeDesc) or
+        # generic proc instantiation:
+        (n[0].kind == nkSym and n[0].sym.isGenericRoutineStrict))
+    if ignoreFirst:
+      result.add(n[0])
+    else:
+      result.add(prepareNode(cl, n[0]))
+    for i in 1..<n.len:
+      result.add(prepareNode(cl, n[i]))
+  of nkDotExpr:
+    # don't try to instantiate RHS of dot expression, it can outright be
+    # undeclared, but definitely instantiate LHS
+    assert n.len >= 2
+    result.add(prepareNode(cl, n[0]))
+    result.add(n[1])
+    for i in 2..<n.len:
+      result.add(prepareNode(cl, n[i]))
+  else:
+    for i in 0..<n.safeLen:
+      result.add(prepareNode(cl, n[i]))
 
 proc isTypeParam(n: PNode): bool =
   # XXX: generic params should use skGenericParam instead of skType
@@ -218,6 +280,9 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PT
   if n == nil: return
   result = copyNode(n)
   if n.typ != nil:
+    if n.typ.kind == tyFromExpr:
+      # type of node should not be evaluated as a static value
+      n.typ.flags.incl tfNonConstExpr
     result.typ = replaceTypeVarsT(cl, n.typ)
     checkMetaInvariants(cl, result.typ)
   case n.kind
@@ -230,7 +295,8 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PT
         replaceTypeVarsS(cl, n.sym, result.typ)
       else:
         replaceTypeVarsS(cl, n.sym, replaceTypeVarsT(cl, n.sym.typ))
-    if result.sym.typ.kind == tyVoid:
+    # sym type can be nil if was gensym created by macro, see #24048
+    if result.sym.typ != nil and result.sym.typ.kind == tyVoid:
       # don't add the 'void' field
       result = newNodeI(nkRecList, n.info)
   of nkRecWhen:
@@ -569,6 +635,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
       result.kind = tyUserTypeClassInst
 
   of tyGenericBody:
+    if cl.allowMetaTypes: return
     localError(
       cl.c.config,
       cl.info,
@@ -587,13 +654,18 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
     assert t.n.typ != t
     var n = prepareNode(cl, t.n)
     if n.kind != nkEmpty:
-      n = cl.c.semConstExpr(cl.c, n)
+      if tfNonConstExpr in t.flags:
+        n = cl.c.semExprWithType(cl.c, n, flags = {efInTypeof})
+      else:
+        n = cl.c.semConstExpr(cl.c, n)
     if n.typ.kind == tyTypeDesc:
       # XXX: sometimes, chained typedescs enter here.
       # It may be worth investigating why this is happening,
       # because it may cause other bugs elsewhere.
       result = n.typ.skipTypes({tyTypeDesc})
       # result = n.typ.base
+    elif tfNonConstExpr in t.flags:
+      result = n.typ
     else:
       if n.typ.kind != tyStatic and n.kind != nkType:
         # XXX: In the future, semConstExpr should
@@ -619,8 +691,31 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
     elif t.elementType.kind != tyNone:
       result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.elementType))
 
-  of tyUserTypeClass, tyStatic:
+  of tyUserTypeClass:
     result = t
+  
+  of tyStatic:
+    if cl.c.matchedConcept != nil:
+      # allow concepts to not instantiate statics for now
+      # they can't always infer them
+      return
+    if not containsGenericType(t) and (t.n == nil or t.n.kind in nkLiterals):
+      # no need to instantiate
+      return
+    bailout()
+    result = instCopyType(cl, t)
+    cl.localCache[t.itemId] = result
+    for i in FirstGenericParamAt..<result.kidsLen:
+      var r = result[i]
+      if r != nil:
+        r = replaceTypeVarsT(cl, r)
+        result[i] = r
+        propagateToOwner(result, r)
+    result.n = replaceTypeVarsN(cl, result.n)
+    if not cl.allowMetaTypes and result.n != nil and
+        result.base.kind != tyNone:
+      result.n = cl.c.semConstExpr(cl.c, result.n)
+      result.n.typ = result.base
 
   of tyGenericInst, tyUserTypeClassInst:
     bailout()
@@ -641,7 +736,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
 
       for i, resulti in result.ikids:
         if resulti != nil:
-          if resulti.kind == tyGenericBody:
+          if resulti.kind == tyGenericBody and not cl.allowMetaTypes:
             localError(cl.c.config, if t.sym != nil: t.sym.info else: cl.info,
               "cannot instantiate '" &
               typeToString(result[i], preferDesc) &
@@ -706,6 +801,14 @@ proc replaceTypesInBody*(p: PContext, pt: TypeMapping, n: PNode;
   result = replaceTypeVarsN(cl, n, expectedType = expectedType)
   popInfoContext(p.config)
 
+proc prepareTypesInBody*(p: PContext, pt: TypeMapping, n: PNode;
+                         owner: PSym = nil): PNode =
+  var typeMap = initLayeredTypeMap(pt)
+  var cl = initTypeVars(p, typeMap, n.info, owner)
+  pushInfoContext(p.config, n.info)
+  result = prepareNode(cl, n)
+  popInfoContext(p.config)
+
 when false:
   # deadcode
   proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode;
diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim
index 1b75f6be6..d8dfe1828 100644
--- a/compiler/sighashes.nim
+++ b/compiler/sighashes.nim
@@ -55,6 +55,8 @@ proc hashSym(c: var MD5Context, s: PSym) =
       c &= it.name.s
       c &= "."
       it = it.owner
+    c &= "#"
+    c &= s.disamb
 
 proc hashTypeSym(c: var MD5Context, s: PSym; conf: ConfigRef) =
   if sfAnon in s.flags or s.kind == skGenericParam:
@@ -69,6 +71,8 @@ proc hashTypeSym(c: var MD5Context, s: PSym; conf: ConfigRef) =
       c &= it.name.s
       c &= "."
       it = it.owner
+    c &= "#"
+    c &= s.disamb
 
 proc hashTree(c: var MD5Context, n: PNode; flags: set[ConsiderFlag]; conf: ConfigRef) =
   if n == nil:
@@ -154,9 +158,9 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
     # is actually safe without an infinite recursion check:
     if t.sym != nil:
       if {sfCompilerProc} * t.sym.flags != {}:
-        doAssert t.sym.loc.r != ""
+        doAssert t.sym.loc.snippet != ""
         # The user has set a specific name for this type
-        c &= t.sym.loc.r
+        c &= t.sym.loc.snippet
       elif CoOwnerSig in flags:
         c.hashTypeSym(t.sym, conf)
       else:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 30ce24500..6ea2c7bb5 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -23,7 +23,8 @@ when defined(nimPreviewSlimSystem):
 type
   MismatchKind* = enum
     kUnknown, kAlreadyGiven, kUnknownNamedParam, kTypeMismatch, kVarNeeded,
-    kMissingParam, kExtraArg, kPositionalAlreadyGiven
+    kMissingParam, kExtraArg, kPositionalAlreadyGiven,
+    kGenericParamTypeMismatch, kMissingGenericParam, kExtraGenericParam
 
   MismatchInfo* = object
     kind*: MismatchKind # reason for mismatch
@@ -59,8 +60,8 @@ type
     magic*: TMagic           # magic of operation
     baseTypeMatch: bool      # needed for conversions from T to openarray[T]
                              # for example
-    fauxMatch*: TTypeKind    # the match was successful only due to the use
-                             # of error or wildcard (unknown) types.
+    matchedErrorType*: bool  # match is considered successful after matching
+                             # error type to avoid cascading errors
                              # this is used to prevent instantiations.
     genericConverter*: bool  # true if a generic converter needs to
                              # be instantiated
@@ -80,7 +81,8 @@ type
                               # or when the explain pragma is used. may be
                               # triggered with an idetools command in the
                               # future.
-    inheritancePenalty: int   # to prefer closest father object type
+                              # to prefer closest father object type
+    inheritancePenalty: int
     firstMismatch*: MismatchInfo # mismatch info for better error messages
     diagnosticsEnabled*: bool
 
@@ -95,19 +97,18 @@ type
 
 const
   isNilConversion = isConvertible # maybe 'isIntConv' fits better?
+  maxInheritancePenalty = high(int) div 2
 
-proc markUsed*(c: PContext; info: TLineInfo, s: PSym)
+proc markUsed*(c: PContext; info: TLineInfo, s: PSym; checkStyle = true)
 proc markOwnerModuleAsUsed*(c: PContext; s: PSym)
 
-template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
-
 proc initCandidateAux(ctx: PContext,
                       callee: PType): TCandidate {.inline.} =
   result = TCandidate(c: ctx, exactMatches: 0, subtypeMatches: 0,
                       convMatches: 0, intConvMatches: 0, genericMatches: 0,
                       state: csEmpty, firstMismatch: MismatchInfo(),
                       callee: callee, call: nil, baseTypeMatch: false,
-                      genericConverter: false, inheritancePenalty: 0
+                      genericConverter: false, inheritancePenalty: -1
   )
 
 proc initCandidate*(ctx: PContext, callee: PType): TCandidate =
@@ -129,6 +130,110 @@ proc put(c: var TCandidate, key, val: PType) {.inline.} =
       echo "binding ", key, " -> ", val
   idTablePut(c.bindings, key, val.skipIntLit(c.c.idgen))
 
+proc typeRel*(c: var TCandidate, f, aOrig: PType,
+              flags: TTypeRelFlags = {}): TTypeRelation
+
+proc matchGenericParam(m: var TCandidate, formal: PType, n: PNode) =
+  var arg = n.typ
+  if m.c.inGenericContext > 0:
+    # don't match yet-unresolved generic instantiations
+    while arg != nil and arg.kind == tyGenericParam:
+      arg = idTableGet(m.bindings, arg)
+    if arg == nil or arg.containsUnresolvedType:
+      m.state = csNoMatch
+      return
+  # fix up the type to get ready to match formal:
+  var formalBase = formal
+  while formalBase.kind == tyGenericParam and
+      formalBase.genericParamHasConstraints:
+    formalBase = formalBase.genericConstraint
+  if formalBase.kind == tyStatic and arg.kind != tyStatic:
+    # maybe call `paramTypesMatch` here, for now be conservative
+    if n.kind in nkSymChoices: n.flags.excl nfSem
+    let evaluated = m.c.semTryConstExpr(m.c, n, formalBase.skipTypes({tyStatic}))
+    if evaluated != nil:
+      arg = newTypeS(tyStatic, m.c, son = evaluated.typ)
+      arg.n = evaluated
+  elif formalBase.kind == tyTypeDesc:
+    if arg.kind != tyTypeDesc:
+      arg = makeTypeDesc(m.c, arg)
+  else:
+    arg = arg.skipTypes({tyTypeDesc})
+  let tm = typeRel(m, formal, arg)
+  if tm in {isNone, isConvertible}:
+    m.state = csNoMatch
+    m.firstMismatch.kind = kGenericParamTypeMismatch
+    return
+
+proc matchGenericParams*(m: var TCandidate, binding: PNode, callee: PSym) =
+  ## matches explicit generic instantiation `binding` against generic params of
+  ## proc symbol `callee`
+  ## state is set to `csMatch` if all generic params match, `csEmpty` if
+  ## implicit generic parameters are missing (matches but cannot instantiate),
+  ## `csNoMatch` if a constraint fails or param count doesn't match
+  let c = m.c
+  let typeParams = callee.ast[genericParamsPos]
+  let paramCount = typeParams.len
+  let bindingCount = binding.len-1
+  if bindingCount > paramCount:
+    m.state = csNoMatch
+    m.firstMismatch.kind = kExtraGenericParam
+    m.firstMismatch.arg = paramCount + 1
+    return
+  for i in 1..bindingCount:
+    matchGenericParam(m, typeParams[i-1].typ, binding[i])
+    if m.state == csNoMatch:
+      m.firstMismatch.arg = i
+      m.firstMismatch.formal = typeParams[i-1].sym
+      return
+  # not enough generic params given, check if remaining have defaults:
+  for i in bindingCount ..< paramCount:
+    let param = typeParams[i]
+    assert param.kind == nkSym
+    let paramSym = param.sym
+    if paramSym.ast != nil:
+      matchGenericParam(m, param.typ, paramSym.ast)
+      if m.state == csNoMatch:
+        m.firstMismatch.arg = i + 1
+        m.firstMismatch.formal = paramSym
+        return
+    elif tfImplicitTypeParam in paramSym.typ.flags:
+      # not a mismatch, but can't create sym
+      m.state = csEmpty
+      return
+    else:
+      m.state = csNoMatch
+      m.firstMismatch.kind = kMissingGenericParam
+      m.firstMismatch.arg = i + 1
+      m.firstMismatch.formal = paramSym
+      return
+  m.state = csMatch
+
+proc copyingEraseVoidParams(m: TCandidate, t: var PType) =
+  ## if `t` is a proc type with void parameters, copies it and erases them
+  assert t.kind == tyProc
+  let original = t
+  var copied = false
+  for i in 1 ..< original.len:
+    var f = original[i]
+    var isVoidParam = f.kind == tyVoid
+    if not isVoidParam:
+      let prev = idTableGet(m.bindings, f)
+      if prev != nil: f = prev
+      isVoidParam = f.kind == tyVoid
+    if isVoidParam:
+      if not copied:
+        # keep first i children
+        t = copyType(original, m.c.idgen, t.owner)
+        t.setSonsLen(i)
+        t.n = copyNode(original.n)
+        t.n.sons = original.n.sons
+        t.n.sons.setLen(i)
+        copied = true
+    elif copied:
+      t.add(f)
+      t.n.add(original.n[i])
+
 proc initCandidate*(ctx: PContext, callee: PSym,
                     binding: PNode, calleeScope = -1,
                     diagnosticsEnabled = false): TCandidate =
@@ -143,17 +248,20 @@ proc initCandidate*(ctx: PContext, callee: PSym,
   result.magic = result.calleeSym.magic
   result.bindings = initTypeMapping()
   if binding != nil and callee.kind in routineKinds:
-    var typeParams = callee.ast[genericParamsPos]
-    for i in 1..min(typeParams.len, binding.len-1):
-      var formalTypeParam = typeParams[i-1].typ
-      var bound = binding[i].typ
-      if bound != nil:
-        if formalTypeParam.kind == tyTypeDesc:
-          if bound.kind != tyTypeDesc:
-            bound = makeTypeDesc(ctx, bound)
-        else:
-          bound = bound.skipTypes({tyTypeDesc})
-        put(result, formalTypeParam, bound)
+    matchGenericParams(result, binding, callee)
+    let genericMatch = result.state
+    if genericMatch != csNoMatch:
+      result.state = csEmpty
+      if genericMatch == csMatch: # csEmpty if not fully instantiated
+        # instantiate the type, emulates old compiler behavior
+        # wouldn't be needed if sigmatch could handle complex cases,
+        # examples are in texplicitgenerics
+        # might be buggy, see rest of generateInstance if problems occur
+        let typ = ctx.instantiateOnlyProcType(ctx, result.bindings, callee, binding.info)
+        result.callee = typ
+      else:
+        # createThread[void] requires this if the above branch is removed:
+        copyingEraseVoidParams(result, result.callee)
 
 proc newCandidate*(ctx: PContext, callee: PSym,
                    binding: PNode, calleeScope = -1): TCandidate =
@@ -176,9 +284,6 @@ proc copyCandidate(dest: var TCandidate, src: TCandidate) =
   dest.baseTypeMatch = src.baseTypeMatch
   dest.bindings = src.bindings
 
-proc typeRel*(c: var TCandidate, f, aOrig: PType,
-              flags: TTypeRelFlags = {}): TTypeRelation
-
 proc checkGeneric(a, b: TCandidate): int =
   let c = a.c
   let aa = a.callee
@@ -287,6 +392,15 @@ proc writeMatches*(c: TCandidate) =
   echo "  conv matches: ", c.convMatches
   echo "  inheritance: ", c.inheritancePenalty
 
+proc cmpInheritancePenalty(a, b: int): int =
+  var eb = b
+  var ea = a
+  if b < 0:
+    eb = maxInheritancePenalty  # defacto max penalty
+  if a < 0:
+    ea = maxInheritancePenalty
+  eb - ea
+
 proc cmpCandidates*(a, b: TCandidate, isFormal=true): int =
   result = a.exactMatches - b.exactMatches
   if result != 0: return
@@ -298,8 +412,7 @@ proc cmpCandidates*(a, b: TCandidate, isFormal=true): int =
   if result != 0: return
   result = a.convMatches - b.convMatches
   if result != 0: return
-  # the other way round because of other semantics:
-  result = b.inheritancePenalty - a.inheritancePenalty
+  result = cmpInheritancePenalty(a.inheritancePenalty, b.inheritancePenalty)
   if result != 0: return
   if isFormal:
     # check for generic subclass relation
@@ -328,16 +441,27 @@ template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = p
     result.add renderTree(n[i][0])
     result.add ": "
     if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
-      # XXX we really need to 'tryExpr' here!
-      arg = c.semOperand(c, n[i][1])
-      n[i].typ = arg.typ
-      n[i][1] = arg
+      arg = c.semTryExpr(c, n[i][1])
+      if arg == nil:
+        arg = n[i][1]
+        arg.typ = newTypeS(tyUntyped, c)
+      else:
+        if arg.typ == nil:
+          arg.typ = newTypeS(tyVoid, c)
+        n[i].typ = arg.typ
+        n[i][1] = arg
   else:
     if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse,
                                           nkOfBranch, nkElifBranch,
                                           nkExceptBranch}:
-      arg = c.semOperand(c, n[i])
-      n[i] = arg
+      arg = c.semTryExpr(c, n[i])
+      if arg == nil:
+        arg = n[i]
+        arg.typ = newTypeS(tyUntyped, c)
+      else:
+        if arg.typ == nil:
+          arg.typ = newTypeS(tyVoid, c)
+        n[i] = arg
   if arg.typ != nil and arg.typ.kind == tyError: return
   result.add argTypeToString(arg, prefer)
 
@@ -361,6 +485,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
     else: result = t
   of tyGenericParam, tyAnything, tyConcept:
     result = t
+    if c.isNoCall: return
     while true:
       result = idTableGet(c.bindings, t)
       if result == nil:
@@ -388,9 +513,16 @@ proc handleRange(c: PContext, f, a: PType, min, max: TTypeKind): TTypeRelation =
     let k = ab.kind
     let nf = c.config.normalizeKind(f.kind)
     let na = c.config.normalizeKind(k)
-    if k == f.kind: result = isSubrange
-    elif k == tyInt and f.kind in {tyRange, tyInt..tyInt64,
-                                   tyUInt..tyUInt64} and
+    if k == f.kind:
+      # `a` is a range type matching its base type
+      # see very bottom for range types matching different types
+      if isIntLit(ab):
+        # range type can only give isFromIntLit for base type
+        result = isFromIntLit
+      else:
+        result = isSubrange
+    elif a.kind == tyInt and f.kind in {tyRange, tyInt..tyInt64,
+                                        tyUInt..tyUInt64} and
         isIntLit(ab) and getInt(ab.n) >= firstOrd(nil, f) and
                          getInt(ab.n) <= lastOrd(nil, f):
       # passing 'nil' to firstOrd/lastOrd here as type checking rules should
@@ -588,10 +720,9 @@ proc recordRel(c: var TCandidate, f, a: PType, flags: TTypeRelFlags): TTypeRelat
     let firstField = if f.kind == tyTuple: 0
                      else: 1
     for _, ff, aa in tupleTypePairs(f, a):
-      let oldInheritancePenalty = c.inheritancePenalty
       var m = typeRel(c, ff, aa, flags)
       if m < isSubtype: return isNone
-      if m == isSubtype and c.inheritancePenalty > oldInheritancePenalty:
+      if m == isSubtype and aa.kind != tyNil and c.inheritancePenalty > -1:
         # we can't process individual element type conversions from a
         # type conversion for the whole tuple
         # subtype relations need type conversions when inheritance is used
@@ -677,6 +808,8 @@ proc procParamTypeRel(c: var TCandidate; f, a: PType): TTypeRelation =
 proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   case a.kind
   of tyProc:
+    var f = f
+    copyingEraseVoidParams(c, f)
     if f.signatureLen != a.signatureLen: return
     result = isEqual      # start with maximum; also correct for no
                           # params at all
@@ -786,7 +919,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
             param.typ.flags.incl tfInferrableStatic
           else:
             param.ast = typ.n
-        of tyUnknown:
+        of tyFromExpr:
           param = paramSym skVar
           param.typ = typ.exactReplica
           #copyType(typ, c.idgen, typ.owner)
@@ -865,6 +998,7 @@ proc maybeSkipDistinct(m: TCandidate; t: PType, callee: PSym): PType =
 
 proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
                             allowUnresolved = false,
+                            allowCalls = false,
                             expectedType: PType = nil): PNode =
   # Consider this example:
   #   type Value[N: static[int]] = object
@@ -874,7 +1008,7 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
   # This proc is used to evaluate such static expressions.
   let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil,
                                         allowMetaTypes = allowUnresolved)
-  if instantiated.kind in nkCallKinds:
+  if not allowCalls and instantiated.kind in nkCallKinds:
     return nil
   result = c.c.semExpr(c.c, instantiated)
 
@@ -946,7 +1080,8 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
 
     else: discard
 
-  elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil:
+  elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and
+      (lhs.typ.n == nil or idTableGet(c.bindings, lhs.typ) == nil):
     var inferred = newTypeS(tyStatic, c.c, lhs.typ.elementType)
     inferred.n = newIntNode(nkIntLit, rhs)
     put(c, lhs.typ, inferred)
@@ -990,9 +1125,21 @@ proc inferStaticsInRange(c: var TCandidate,
     doInferStatic(lowerBound, getInt(upperBound) + 1 - lengthOrd(c.c.config, concrete))
 
 template subtypeCheck() =
-  if result <= isSubrange and f.last.skipTypes(abstractInst).kind in {
-      tyRef, tyPtr, tyVar, tyLent, tyOwned}:
+  case result
+  of isIntConv:
     result = isNone
+  of isSubrange:
+    discard # XXX should be isNone with preview define, warnings
+  of isConvertible:
+    if f.last.skipTypes(abstractInst).kind != tyOpenArray:
+      # exclude var openarray which compiler supports
+      result = isNone
+  of isSubtype:
+    if f.last.skipTypes(abstractInst).kind in {
+        tyRef, tyPtr, tyVar, tyLent, tyOwned}:
+      # compiler can't handle subtype conversions with pointer indirection
+      result = isNone
+  else: discard
 
 proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
   # this proc is always called for a pair of matching types
@@ -1144,6 +1291,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     if prev == nil: body
     else: return typeRel(c, prev, a, flags)
 
+  if c.c.inGenericContext > 0 and not c.isNoCall and
+      (tfUnresolved in a.flags or a.kind in tyTypeClasses):
+    # cheap check for unresolved arg, not nested
+    return isNone
+
   case a.kind
   of tyOr:
     # XXX: deal with the current dual meaning of tyGenericParam
@@ -1196,10 +1348,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
         return isGeneric
   of tyFromExpr:
     if c.c.inGenericContext > 0:
-      # generic type bodies can sometimes compile call expressions
-      # prevent expressions with unresolved types from
-      # being passed as parameters
-      return isNone
+      if not c.isNoCall:
+        # generic type bodies can sometimes compile call expressions
+        # prevent expressions with unresolved types from
+        # being passed as parameters
+        return isNone
+      else:
+        # Foo[templateCall(T)] shouldn't fail early if Foo has a constraint
+        # and we can't evaluate `templateCall(T)` yet
+        return isGeneric
   else: discard
 
   case f.kind
@@ -1260,13 +1417,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     subtypeCheck()
   of tyArray:
     a = reduceToBase(a)
-    case a.kind
-    of tyArray:
+    if a.kind == tyArray:
       var fRange = f.indexType
       var aRange = a.indexType
       if fRange.kind in {tyGenericParam, tyAnything}:
         var prev = idTableGet(c.bindings, fRange)
         if prev == nil:
+          if typeRel(c, fRange, aRange) == isNone:
+            return isNone
           put(c, fRange, a.indexType)
           fRange = a
         else:
@@ -1279,7 +1437,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
         result = isGeneric
       else:
         result = typeRel(c, ff, aa, flags)
-
       if result < isGeneric:
         if nimEnableCovariance and
            trNoCovariance notin flags and
@@ -1290,6 +1447,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
           return isNone
 
       if fRange.rangeHasUnresolvedStatic:
+        if aRange.kind in {tyGenericParam} and aRange.reduceToBase() == aRange:
+          return
         return inferStaticsInRange(c, fRange, a)
       elif c.c.matchedConcept != nil and aRange.rangeHasUnresolvedStatic:
         return inferStaticsInRange(c, aRange, f)
@@ -1298,12 +1457,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       else:
         if lengthOrd(c.c.config, fRange) != lengthOrd(c.c.config, aRange):
           result = isNone
-    else: discard
-  of tyUncheckedArray:
-    if a.kind == tyUncheckedArray:
-      result = typeRel(c, elementType(f), elementType(a), flags)
-      if result < isGeneric: result = isNone
-    else: discard
   of tyOpenArray, tyVarargs:
     # varargs[untyped] is special too but handled earlier. So we only need to
     # handle varargs[typed]:
@@ -1344,9 +1497,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
             typeRel(c, base(f), base(a), flags) >= isGeneric:
           result = isConvertible
     else: discard
-  of tySequence:
-    case a.kind
-    of tySequence:
+  of tySequence, tyUncheckedArray:
+    if a.kind == f.kind:
       if (f[0].kind != tyGenericParam) and (a.elementType.kind == tyEmpty):
         result = isSubtype
       else:
@@ -1361,8 +1513,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
             result = isSubtype
           else:
             result = isNone
-    of tyNil: result = isNone
-    else: discard
+    elif a.kind == tyNil:
+      result = isNone
   of tyOrdinal:
     if isOrdinalType(a):
       var x = if a.kind == tyOrdinal: a.elementType else: a
@@ -1388,12 +1540,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
         reduceToBase(a)
     if effectiveArgType.kind == tyObject:
       if sameObjectTypes(f, effectiveArgType):
+        c.inheritancePenalty = if tfFinal in f.flags: -1 else: 0
         result = isEqual
         # elif tfHasMeta in f.flags: result = recordRel(c, f, a)
       elif trIsOutParam notin flags:
-        var depth = isObjectSubtype(c, effectiveArgType, f, nil)
-        if depth > 0:
-          inc(c.inheritancePenalty, depth)
+        c.inheritancePenalty = isObjectSubtype(c, effectiveArgType, f, nil)
+        if c.inheritancePenalty > 0:
           result = isSubtype
   of tyDistinct:
     a = a.skipTypes({tyOwned, tyGenericInst, tyRange})
@@ -1409,11 +1561,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       else:
         result = typeRel(c, f[0], a[0], flags)
         if result < isGeneric:
-          if result <= isConvertible:
-            result = isNone
-          elif tfIsConstructor notin a.flags:
-            # set constructors are a bit special...
+          if tfIsConstructor notin a.flags:
+            # set['a'..'z'] and set[char] have different representations
             result = isNone
+          else:
+            # but we can convert individual elements of the constructor
+            result = isConvertible
   of tyPtr, tyRef:
     a = reduceToBase(a)
     if a.kind == f.kind:
@@ -1562,7 +1715,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
         if aAsObject.kind == tyObject and trIsOutParam notin flags:
           let baseType = aAsObject.base
           if baseType != nil:
-            c.inheritancePenalty += 1
+            inc c.inheritancePenalty, 1 + int(c.inheritancePenalty < 0)
             let ret = typeRel(c, f, baseType, flags)
             return if ret in {isEqual,isGeneric}: isSubtype else: ret
 
@@ -1659,7 +1812,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
           depth = -1
 
       if depth >= 0:
-        c.inheritancePenalty += depth
+        inc c.inheritancePenalty, depth + int(c.inheritancePenalty < 0)
         # bug #4863: We still need to bind generic alias crap, so
         # we cannot return immediately:
         result = if depth == 0: isGeneric else: isSubtype
@@ -1677,19 +1830,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     considerPreviousT:
       result = isNone
       let oldInheritancePenalty = c.inheritancePenalty
-      var maxInheritance = 0
+      var minInheritance = maxInheritancePenalty
       for branch in f.kids:
-        c.inheritancePenalty = 0
+        c.inheritancePenalty = -1
         let x = typeRel(c, branch, aOrig, flags)
-        maxInheritance = max(maxInheritance, c.inheritancePenalty)
-        # 'or' implies maximum matching result:
-        if x > result: result = x
+        if x >= result:
+          if  c.inheritancePenalty > -1:
+            minInheritance = min(minInheritance, c.inheritancePenalty)
+          result = x
       if result >= isIntConv:
+        if minInheritance < maxInheritancePenalty:
+          c.inheritancePenalty = oldInheritancePenalty + minInheritance
         if result > isGeneric: result = isGeneric
         bindingRet result
       else:
         result = isNone
-      c.inheritancePenalty = oldInheritancePenalty + maxInheritance
   of tyNot:
     considerPreviousT:
       if typeRel(c, f.elementType, aOrig, flags) != isNone:
@@ -1799,18 +1954,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       else:
         # check if 'T' has a constraint as in 'proc p[T: Constraint](x: T)'
         if f.len > 0 and f[0].kind != tyNone:
-          let oldInheritancePenalty = c.inheritancePenalty
           result = typeRel(c, f[0], a, flags + {trDontBind, trBindGenericParam})
           if doBindGP and result notin {isNone, isGeneric}:
             let concrete = concreteType(c, a, f)
             if concrete == nil: return isNone
             put(c, f, concrete)
-          # bug #6526
           if result in {isEqual, isSubtype}:
-            # 'T: Class' is a *better* match than just 'T'
-            # but 'T: Subclass' is even better:
-            c.inheritancePenalty = oldInheritancePenalty - c.inheritancePenalty -
-                                  100 * ord(result == isEqual)
             result = isGeneric
         elif a.kind == tyTypeDesc:
           # somewhat special typing rule, the following is illegal:
@@ -1843,16 +1992,29 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     elif x.kind == tyGenericParam:
       result = isGeneric
     else:
+      # This is the bound type - can't benifit from these tallies
+      let
+        inheritancePenaltyOld = c.inheritancePenalty
       result = typeRel(c, x, a, flags) # check if it fits
+      c.inheritancePenalty = inheritancePenaltyOld
       if result > isGeneric: result = isGeneric
   of tyStatic:
     let prev = idTableGet(c.bindings, f)
     if prev == nil:
       if aOrig.kind == tyStatic:
-        if f.base.kind notin {tyNone, tyGenericParam}:
+        if c.c.inGenericContext > 0 and aOrig.n == nil and not c.isNoCall:
+          # don't match unresolved static value to static param to avoid
+          # faulty instantiations in calls in generic bodies
+          # but not for generic invocations as they only check constraints
+          result = isNone
+        elif f.base.kind notin {tyNone, tyGenericParam}:
           result = typeRel(c, f.base, a, flags)
           if result != isNone and f.n != nil:
-            if not exprStructuralEquivalent(f.n, aOrig.n):
+            var r = tryResolvingStaticExpr(c, f.n)
+            if r == nil: r = f.n
+            if not exprStructuralEquivalent(r, aOrig.n) and
+                not (aOrig.n != nil and aOrig.n.kind == nkIntLit and
+                  inferStaticParam(c, r, aOrig.n.intVal)):
               result = isNone
         elif f.base.kind == tyGenericParam:
           # Handling things like `type A[T; Y: static T] = object`
@@ -1904,8 +2066,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
       # proc foo(T: typedesc, x: T)
       # when `f` is an unresolved typedesc, `a` could be any
       # type, so we should not perform this check earlier
-      if c.c.inGenericContext > 0 and
-          a.skipTypes({tyTypeDesc}).kind == tyGenericParam:
+      if c.c.inGenericContext > 0 and a.containsUnresolvedType:
         # generic type bodies can sometimes compile call expressions
         # prevent unresolved generic parameters from being passed to procs as
         # typedesc parameters
@@ -1934,28 +2095,36 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     if aOrig != nil:
       put(c, f, aOrig)
     result = isGeneric
-  of tyProxy:
+  of tyError:
     result = isEqual
   of tyFromExpr:
     # fix the expression, so it contains the already instantiated types
     if f.n == nil or f.n.kind == nkEmpty: return isGeneric
-    let reevaluated = tryResolvingStaticExpr(c, f.n)
-    if reevaluated == nil:
+    if c.c.inGenericContext > 0:
+      # need to delay until instantiation
+      # also prevent infinite recursion below
+      return isNone
+    inc c.c.inGenericContext # to generate tyFromExpr again if unresolved
+    # use prepareNode for consistency with other tyFromExpr in semtypinst:
+    let instantiated = prepareTypesInBody(c.c, c.bindings, f.n)
+    let reevaluated = c.c.semExpr(c.c, instantiated).typ
+    dec c.c.inGenericContext
+    case reevaluated.kind
+    of tyFromExpr:
+      # not resolved
       result = isNone
-      return
-    case reevaluated.typ.kind
     of tyTypeDesc:
-      result = typeRel(c, a, reevaluated.typ.base, flags)
+      result = typeRel(c, reevaluated.base, a, flags)
     of tyStatic:
-      result = typeRel(c, a, reevaluated.typ.base, flags)
-      if result != isNone and reevaluated.typ.n != nil:
-        if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
+      result = typeRel(c, reevaluated.base, a, flags)
+      if result != isNone and reevaluated.n != nil:
+        if not exprStructuralEquivalent(aOrig.n, reevaluated.n):
           result = isNone
     else:
       # bug #14136: other types are just like 'tyStatic' here:
-      result = typeRel(c, a, reevaluated.typ, flags)
-      if result != isNone and reevaluated.typ.n != nil:
-        if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
+      result = typeRel(c, reevaluated, a, flags)
+      if result != isNone and reevaluated.n != nil:
+        if not exprStructuralEquivalent(aOrig.n, reevaluated.n):
           result = isNone
   of tyNone:
     if a.kind == tyNone: result = isEqual
@@ -1994,7 +2163,7 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
                   c: PContext): PNode =
   result = newNodeI(kind, arg.info)
   if containsGenericType(f):
-    if not m.hasFauxMatch:
+    if not m.matchedErrorType:
       result.typ = getInstantiatedType(c, arg, m, f).skipTypes({tySink})
     else:
       result.typ = errorType(c)
@@ -2015,6 +2184,81 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
   else:
     result.add arg
 
+proc convertLiteral(kind: TNodeKind, c: PContext, m: TCandidate; n: PNode, newType: PType): PNode =
+  # based off changeType but generates implicit conversions instead
+  template addConsiderNil(s, node) =
+    let val = node
+    if val.isNil: return nil
+    s.add(val)
+  case n.kind
+  of nkCurly:
+    result = copyNode(n)
+    for i in 0..<n.len:
+      if n[i].kind == nkRange:
+        var x = copyNode(n[i])
+        x.addConsiderNil convertLiteral(kind, c, m, n[i][0], elemType(newType))
+        x.addConsiderNil convertLiteral(kind, c, m, n[i][1], elemType(newType))
+        result.add x
+      else:
+        result.addConsiderNil convertLiteral(kind, c, m, n[i], elemType(newType))
+    result.typ = newType
+    return
+  of nkBracket:
+    result = copyNode(n)
+    for i in 0..<n.len:
+      result.addConsiderNil convertLiteral(kind, c, m, n[i], elemType(newType))
+    result.typ = newType
+    return
+  of nkPar, nkTupleConstr:
+    let tup = newType.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
+    if tup.kind == tyTuple:
+      result = copyNode(n)
+      if n.len > 0 and n[0].kind == nkExprColonExpr:
+        # named tuple?
+        for i in 0..<n.len:
+          var name = n[i][0]
+          if name.kind != nkSym:
+            #globalError(c.config, name.info, "invalid tuple constructor")
+            return nil
+          if tup.n != nil:
+            var f = getSymFromList(tup.n, name.sym.name)
+            if f == nil:
+              #globalError(c.config, name.info, "unknown identifier: " & name.sym.name.s)
+              return nil
+            result.addConsiderNil convertLiteral(kind, c, m, n[i][1], f.typ)
+          else:
+            result.addConsiderNil convertLiteral(kind, c, m, n[i][1], tup[i])
+      else:
+        for i in 0..<n.len:
+          result.addConsiderNil convertLiteral(kind, c, m, n[i], tup[i])
+      result.typ = newType
+      return
+  of nkCharLit..nkUInt64Lit:
+    if n.kind != nkUInt64Lit and not sameTypeOrNil(n.typ, newType) and isOrdinalType(newType):
+      let value = n.intVal
+      if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
+        return nil
+      result = copyNode(n)
+      result.typ = newType
+      return
+  of nkFloatLit..nkFloat64Lit:
+    if newType.skipTypes(abstractVarRange-{tyTypeDesc}).kind == tyFloat:
+      if not floatRangeCheck(n.floatVal, newType):
+        return nil
+      result = copyNode(n)
+      result.typ = newType
+      return
+  of nkSym:
+    if n.sym.kind == skEnumField and not sameTypeOrNil(n.sym.typ, newType) and isOrdinalType(newType):
+      let value = n.sym.position
+      if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
+        return nil
+      result = copyNode(n)
+      result.typ = newType
+      return
+  else: discard
+  return implicitConv(kind, newType, n, m, c)
+
 proc isLValue(c: PContext; n: PNode, isOutParam = false): bool {.inline.} =
   let aa = isAssignable(nil, n)
   case aa
@@ -2152,6 +2396,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
          a.n == nil and
          tfGenericTypeParam notin a.flags:
         return newNodeIT(nkType, argOrig.info, makeTypeFromExpr(c, arg))
+    elif a.kind == tyFromExpr and c.inGenericContext > 0:
+      # don't try to evaluate
+      discard
     elif arg.kind != nkEmpty:
       var evaluated = c.semTryConstExpr(c, arg)
       if evaluated != nil:
@@ -2223,7 +2470,20 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
     if f.skipTypes({tyRange}).kind in {tyInt, tyUInt}:
       inc(m.convMatches)
     inc(m.convMatches)
-    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+    if skipTypes(f, abstractVar-{tyTypeDesc}).kind == tySet:
+      if tfIsConstructor in a.flags and arg.kind == nkCurly:
+        # we marked the set as convertible only because the arg is a literal
+        # in which case we individually convert each element
+        let t =
+          if containsGenericType(f):
+            getInstantiatedType(c, arg, m, f).skipTypes({tySink})
+          else:
+            f.skipTypes({tySink})
+        result = convertLiteral(nkHiddenStdConv, c, m, arg, t)
+      else:
+        result = nil
+    else:
+      result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isIntConv:
     # I'm too lazy to introduce another ``*matches`` field, so we conflate
     # ``isIntConv`` and ``isIntLit`` here:
@@ -2256,8 +2516,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
     inc(m.genericMatches)
     if arg.typ == nil:
       result = arg
-    elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or
-         m.inheritancePenalty > oldInheritancePenalty:
+    elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or cmpInheritancePenalty(oldInheritancePenalty, m.inheritancePenalty) > 0:
       result = implicitConv(nkHiddenSubConv, f, arg, m, c)
     elif arg.typ.isEmptyContainer:
       result = arg.copyTree
@@ -2283,13 +2542,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
       result = implicitConv(nkHiddenSubConv, f, arg, m, c)
   of isNone:
     # do not do this in ``typeRel`` as it then can't infer T in ``ref T``:
-    if a.kind in {tyProxy, tyUnknown}:
-      if a.kind == tyUnknown and c.inGenericContext > 0:
-        # don't bother with fauxMatch mechanism in generic type,
-        # reject match, typechecking will be delayed to instantiation
-        return nil
+    if a.kind == tyFromExpr: return nil
+    elif a.kind == tyError:
       inc(m.genericMatches)
-      m.fauxMatch = a.kind
+      m.matchedErrorType = true
       return arg
     elif a.kind == tyVoid and f.matchesVoidProc and argOrig.kind == nkStmtList:
       # lift do blocks without params to lambdas
@@ -2358,7 +2614,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     result = paramTypesMatchAux(m, f, a, arg, argOrig)
   else:
     # symbol kinds that don't participate in symchoice type disambiguation:
-    let matchSet = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage, skType}
+    let matchSet = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage}
 
     var best = -1
     result = arg
@@ -2403,6 +2659,12 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
         if arg[i].sym.kind in matchSet:
           copyCandidate(z, m)
           z.callee = arg[i].typ
+          if arg[i].sym.kind == skType and z.callee.kind != tyTypeDesc:
+            # creating the symchoice with the type sym having typedesc type
+            # breaks a lot of stuff, so we make the typedesc type here
+            # mirrored from `newSymNodeTypeDesc`
+            z.callee = newType(tyTypeDesc, c.idgen, arg[i].sym.owner)
+            z.callee.addSonSkipIntLit(arg[i].sym.typ, c.idgen)
           if tfUnresolved in z.callee.flags: continue
           z.calleeSym = arg[i].sym
           z.calleeScope = cmpScopes(m.c, arg[i].sym)
@@ -2453,7 +2715,7 @@ proc setSon(father: PNode, at: int, son: PNode) =
 # we are allowed to modify the calling node in the 'prepare*' procs:
 proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
   if formal.kind == tyUntyped and formal.len != 1:
-    # {tyTypeDesc, tyUntyped, tyTyped, tyProxy}:
+    # {tyTypeDesc, tyUntyped, tyTyped, tyError}:
     # a.typ == nil is valid
     result = a
   elif a.typ.isNil:
@@ -2491,7 +2753,7 @@ proc arrayConstr(c: PContext, n: PNode): PType =
   result = newTypeS(tyArray, c)
   rawAddSon(result, makeRangeType(c, 0, 0, n.info))
   addSonSkipIntLit(result, skipTypes(n.typ,
-      {tyGenericInst, tyVar, tyLent, tyOrdinal}), c.idgen)
+      {tyVar, tyLent, tyOrdinal}), c.idgen)
 
 proc arrayConstr(c: PContext, info: TLineInfo): PType =
   result = newTypeS(tyArray, c)
@@ -2745,6 +3007,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
       inc m.genericMatches
       inc m.exactMatches
     return
+  # initCandidate may have given csNoMatch if generic params didn't match:
+  if m.state == csNoMatch: return
   var marker = initIntSet()
   matchesAux(c, n, nOrig, m, marker)
   if m.state == csNoMatch: return
@@ -2767,14 +3031,16 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
           m.firstMismatch.formal = formal
           break
       else:
+        # mirrored with updateDefaultParams:
         if formal.ast.kind == nkEmpty:
           # The default param value is set to empty in `instantiateProcType`
           # when the type of the default expression doesn't match the type
           # of the instantiated proc param:
-          localError(c.config, m.call.info,
-                     ("The default parameter '$1' has incompatible type " &
-                      "with the explicitly requested proc instantiation") %
-                      formal.name.s)
+          pushInfoContext(c.config, m.call.info,
+            if m.calleeSym != nil: m.calleeSym.detailedInfo else: "")
+          typeMismatch(c.config, formal.ast.info, formal.typ, formal.ast.typ, formal.ast)
+          popInfoContext(c.config)
+          formal.ast.typ = errorType(c)
         if nfDefaultRefsParam in formal.ast.flags:
           m.call.flags.incl nfDefaultRefsParam
         var defaultValue = copyTree(formal.ast)
diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim
index d114f59da..1dd481ec0 100644
--- a/compiler/sizealignoffsetimpl.nim
+++ b/compiler/sizealignoffsetimpl.nim
@@ -385,6 +385,13 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
         accum.maxAlign = 1
         computeObjectOffsetsFoldFunction(conf, typ.n, true, accum)
       else:
+        if typ.baseClass == nil and lacksMTypeField(typ) and typ.n.len == 1 and
+            typ.n[0].kind == nkSym and
+            typ.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
+          # a dummy field is generated for an object with a single field
+          # with an UncheckedArray type
+          assert accum.offset == 0
+          accum.offset = 1
         computeObjectOffsetsFoldFunction(conf, typ.n, false, accum)
       let paddingAtEnd = int16(accum.finish())
       if typ.sym != nil and
diff --git a/compiler/spawn.nim b/compiler/spawn.nim
index 972d49d3e..58d5a4928 100644
--- a/compiler/spawn.nim
+++ b/compiler/spawn.nim
@@ -109,6 +109,16 @@ stmtList:
 
 """
 
+proc castToVoidPointer(g: ModuleGraph, n: PNode, fvField: PNode): PNode =
+  if g.config.backend == backendCpp:
+    result = fvField
+  else:
+    let ptrType = getSysType(g, n.info, tyPointer)
+    result = newNodeI(nkCast, fvField.info)
+    result.add newNodeI(nkEmpty, fvField.info)
+    result.add fvField
+    result.typ = ptrType
+
 proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
                        varSection, varInit, call, barrier, fv: PNode;
                        idgen: IdGenerator;
@@ -156,8 +166,9 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
     if barrier == nil:
       # by now 'fv' is shared and thus might have beeen overwritten! we need
       # to use the thread-local view instead:
+      let castExpr = castToVoidPointer(g, f, threadLocalProm.newSymNode)
       body.add callCodegenProc(g, "nimFlowVarSignal", threadLocalProm.info,
-        threadLocalProm.newSymNode)
+        castExpr)
   else:
     body.add call
   if barrier != nil:
@@ -413,7 +424,8 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp
     # create flowVar:
     result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1]))
     if barrier == nil:
-      result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info, fvField)
+      let castExpr = castToVoidPointer(g, n, fvField)
+      result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info, castExpr)
 
   elif spawnKind == srByVar:
     var field = newSym(skField, getIdent(g.cache, "fv"), idgen, owner, n.info, g.config.options)
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 616ecd466..a5213086b 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -696,7 +696,7 @@ proc markOwnerModuleAsUsed(c: PContext; s: PSym) =
       else:
         inc i
 
-proc markUsed(c: PContext; info: TLineInfo; s: PSym) =
+proc markUsed(c: PContext; info: TLineInfo; s: PSym; checkStyle = true) =
   let conf = c.config
   incl(s.flags, sfUsed)
   if s.kind == skEnumField and s.owner != nil:
@@ -713,7 +713,8 @@ proc markUsed(c: PContext; info: TLineInfo; s: PSym) =
     if sfError in s.flags: userError(conf, info, s)
   when defined(nimsuggest):
     suggestSym(c.graph, info, s, c.graph.usageSym, false)
-  styleCheckUse(c, info, s)
+  if checkStyle:
+    styleCheckUse(c, info, s)
   markOwnerModuleAsUsed(c, s)
 
 proc safeSemExpr*(c: PContext, n: PNode): PNode =
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 070443b82..8dd24e090 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -56,6 +56,7 @@ type
     contSyms, breakSyms: seq[PSym]  # to transform 'continue' and 'break'
     deferDetected, tooEarly: bool
     isIntroducingNewLocalVars: bool  # true if we are in `introducingNewLocalVars` (don't transform yields)
+    inAddr: bool
     flags: TransformFlags
     graph: ModuleGraph
     idgen: IdGenerator
@@ -97,7 +98,7 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
   r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias, tySink})
   incl(r.flags, sfFromGeneric)
   let owner = getCurrOwner(c)
-  if owner.isIterator and not c.tooEarly:
+  if owner.isIterator and not c.tooEarly and not isDefined(c.graph.config, "nimOptIters"):
     result = freshVarForClosureIter(c.graph, r, c.idgen, owner)
   else:
     result = newSymNode(r)
@@ -176,7 +177,7 @@ proc transformSym(c: PTransf, n: PNode): PNode =
 
 proc freshVar(c: PTransf; v: PSym): PNode =
   let owner = getCurrOwner(c)
-  if owner.isIterator and not c.tooEarly:
+  if owner.isIterator and not c.tooEarly and not isDefined(c.graph.config, "nimOptIters"):
     result = freshVarForClosureIter(c.graph, v, c.idgen, owner)
   else:
     var newVar = copySym(v, c.idgen)
@@ -415,9 +416,15 @@ proc transformYield(c: PTransf, n: PNode): PNode =
       result.add transform(c, v)
 
       for i in 0..<c.transCon.forStmt.len - 2:
-        let lhs = c.transCon.forStmt[i]
-        let rhs = transform(c, newTupleAccess(c.graph, tmp, i))
-        result.add(asgnTo(lhs, rhs))
+        if c.transCon.forStmt[i].kind == nkVarTuple:
+          for j in 0..<c.transCon.forStmt[i].len-1:
+            let lhs = c.transCon.forStmt[i][j]
+            let rhs = transform(c, newTupleAccess(c.graph, newTupleAccess(c.graph, tmp, i), j))
+            result.add(asgnTo(lhs, rhs))
+        else:
+          let lhs = c.transCon.forStmt[i]
+          let rhs = transform(c, newTupleAccess(c.graph, tmp, i))
+          result.add(asgnTo(lhs, rhs))
     else:
       for i in 0..<c.transCon.forStmt.len - 2:
         let lhs = c.transCon.forStmt[i]
@@ -456,6 +463,14 @@ proc transformYield(c: PTransf, n: PNode): PNode =
       let rhs = transform(c, e)
       result.add(asgnTo(lhs, rhs))
 
+
+  # bug #23536; note that the info of forLoopBody should't change
+  for idx in 0 ..< result.len:
+    var changeNode = result[idx]
+    changeNode.info = c.transCon.forStmt.info
+    for i, child in changeNode:
+      child.info = changeNode.info
+
   inc(c.transCon.yieldStmts)
   if c.transCon.yieldStmts <= 1:
     # common case
@@ -466,12 +481,6 @@ proc transformYield(c: PTransf, n: PNode): PNode =
     result.add(introduceNewLocalVars(c, c.transCon.forLoopBody))
     c.isIntroducingNewLocalVars = false
 
-  for idx in 0 ..< result.len:
-    var changeNode = result[idx]
-    changeNode.info = c.transCon.forStmt.info
-    for i, child in changeNode:
-      child.info = changeNode.info
-
 proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
   result = transformSons(c, n)
   # inlining of 'var openarray' iterators; bug #19977
@@ -499,7 +508,15 @@ proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
       elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
         result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen)
   else:
-    if n[0].kind in kinds:
+    if n[0].kind in kinds and
+        not (n[0][0].kind == nkSym and n[0][0].sym.kind == skForVar and
+          n[0][0].typ.skipTypes(abstractVar).kind == tyTuple
+        ) and not (n[0][0].kind == nkSym and n[0][0].sym.kind == skParam and
+          n.typ.kind == tyVar and
+          n.typ.skipTypes(abstractVar).kind == tyOpenArray and
+          n[0][0].typ.skipTypes(abstractVar).kind == tyString)
+        : # elimination is harmful to `for tuple unpack` because of newTupleAccess
+          # it is also harmful to openArrayLoc (var openArray) for strings
       # addr ( deref ( x )) --> x
       result = n[0][0]
       if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
@@ -511,6 +528,7 @@ proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
 
   # we cannot generate a proper thunk here for GC-safety reasons
   # (see internal documentation):
+  if jsNoLambdaLifting in c.graph.config.legacyFeatures and c.graph.config.backend == backendJs: return prc
   result = newNodeIT(nkClosure, prc.info, dest)
   var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
   conv.add(newNodeI(nkEmpty, prc.info))
@@ -634,9 +652,11 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
   case arg.kind
   of nkEmpty..nkNilLit:
     result = paDirectMapping
-  of nkDotExpr, nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr:
+  of nkDotExpr, nkDerefExpr, nkHiddenDeref:
+    result = putArgInto(arg[0], formal)
+  of nkAddr, nkHiddenAddr:
     result = putArgInto(arg[0], formal)
-    #if result == paViaIndirection: result = paFastAsgn
+    if result == paViaIndirection: result = paFastAsgn
   of nkCurly, nkBracket:
     for i in 0..<arg.len:
       if putArgInto(arg[i], formal) != paDirectMapping:
@@ -1059,7 +1079,10 @@ proc transform(c: PTransf, n: PNode): PNode =
   of nkHiddenAddr:
     result = transformAddrDeref(c, n, {nkHiddenDeref})
   of nkAddr:
+    let oldInAddr = c.inAddr
+    c.inAddr = true
     result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref})
+    c.inAddr = oldInAddr
   of nkDerefExpr:
     result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
   of nkHiddenDeref:
@@ -1139,7 +1162,7 @@ proc transform(c: PTransf, n: PNode): PNode =
   let exprIsPointerCast = n.kind in {nkCast, nkConv, nkHiddenStdConv} and
                           n.typ != nil and
                           n.typ.kind == tyPointer
-  if not exprIsPointerCast:
+  if not exprIsPointerCast and not c.inAddr:
     var cnst = getConstExpr(c.module, result, c.idgen, c.graph)
     # we inline constants if they are not complex constants:
     if cnst != nil and not dontInlineConstant(n, cnst):
diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim
index d226b2e06..39193a42d 100644
--- a/compiler/typeallowed.nim
+++ b/compiler/typeallowed.nim
@@ -27,6 +27,7 @@ type
     taProcContextIsNotMacro
     taIsCastable
     taIsDefaultField
+    taVoid # only allow direct void fields of objects/tuples
 
   TTypeAllowedFlags* = set[TTypeAllowedFlag]
 
@@ -60,6 +61,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
   if typ == nil: return nil
   if containsOrIncl(marker, typ.id): return nil
   var t = skipTypes(typ, abstractInst-{tyTypeDesc, tySink})
+
+  let flags = if t.kind == tyVoid: flags else: flags-{taVoid}
   case t.kind
   of tyVar, tyLent:
     if kind in {skProc, skFunc, skConst} and (views notin c.features):
@@ -115,7 +118,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
   of tyStatic:
     if kind notin {skParam}: result = t
   of tyVoid:
-    if taField notin flags: result = t
+    if taVoid notin flags: result = t
   of tyTypeClasses:
     if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
       discard
@@ -184,12 +187,12 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
         t.baseClass != nil and taIsDefaultField notin flags:
       result = t
     else:
-      let flags = flags+{taField}
+      let flags = flags+{taField, taVoid}
       result = typeAllowedAux(marker, t.baseClass, kind, c, flags)
       if result.isNil and t.n != nil:
         result = typeAllowedNode(marker, t.n, kind, c, flags)
   of tyTuple:
-    let flags = flags+{taField}
+    let flags = flags+{taField, taVoid}
     for a in t.kids:
       result = typeAllowedAux(marker, a, kind, c, flags)
       if result != nil: break
@@ -197,7 +200,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
       result = typeAllowedNode(marker, t.n, kind, c, flags)
   of tyEmpty:
     if kind in {skVar, skLet}: result = t
-  of tyProxy:
+  of tyError:
     # for now same as error node; we say it's a valid type as it should
     # prevent cascading errors:
     result = nil
diff --git a/compiler/types.nim b/compiler/types.nim
index e5ce0aea1..a441b0ea2 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -115,7 +115,7 @@ proc isPureObject*(typ: PType): bool =
 proc isUnsigned*(t: PType): bool =
   t.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64}
 
-proc getOrdValue*(n: PNode; onError = high(Int128)): Int128 =
+proc getOrdValueAux*(n: PNode, err: var bool): Int128 =
   var k = n.kind
   if n.typ != nil and n.typ.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64}:
     k = nkUIntLit
@@ -131,13 +131,22 @@ proc getOrdValue*(n: PNode; onError = high(Int128)): Int128 =
     toInt128(n.intVal)
   of nkNilLit:
     int128.Zero
-  of nkHiddenStdConv: getOrdValue(n[1], onError)
+  of nkHiddenStdConv:
+    getOrdValueAux(n[1], err)
   else:
-    # XXX: The idea behind the introduction of int128 was to finally
-    # have all calculations numerically far away from any
-    # overflows. This command just introduces such overflows and
-    # should therefore really be revisited.
-    onError
+    err = true
+    int128.Zero
+
+proc getOrdValue*(n: PNode): Int128 =
+  var err: bool = false
+  result = getOrdValueAux(n, err)
+  #assert err == false
+
+proc getOrdValue*(n: PNode, onError: Int128): Int128 =
+  var err = false
+  result = getOrdValueAux(n, err)
+  if err:
+    result = onError
 
 proc getFloatValue*(n: PNode): BiggestFloat =
   case n.kind
@@ -223,7 +232,11 @@ proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
   if result: return
   if not containsOrIncl(marker, t.id):
     case t.kind
-    of tyGenericInst, tyGenericBody, tyAlias, tySink, tyInferred:
+    of tyGenericBody:
+      # treat as atomic, containsUnresolvedType wants always false,
+      # containsGenericType always gives true
+      discard
+    of tyGenericInst, tyAlias, tySink, tyInferred:
       result = iterOverTypeAux(marker, skipModifier(t), iter, closure)
     else:
       for a in t.kids:
@@ -739,6 +752,16 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       if tfThread in t.flags:
         addSep(prag)
         prag.add("gcsafe")
+      var effectsOfStr = ""
+      for i, a in t.paramTypes:
+        let j = paramTypeToNodeIndex(i)
+        if t.n != nil and j < t.n.len and t.n[j].kind == nkSym and t.n[j].sym.kind == skParam and sfEffectsDelayed in t.n[j].sym.flags:
+          addSep(effectsOfStr)
+          effectsOfStr.add(t.n[j].sym.name.s)
+      if effectsOfStr != "":
+        addSep(prag)
+        prag.add("effectsOf: ")
+        prag.add(effectsOfStr)
       if not hasImplicitRaises and prefer == preferInferredEffects and not isNil(t.owner) and not isNil(t.owner.typ) and not isNil(t.owner.typ.n) and (t.owner.typ.n.len > 0):
         let effects = t.owner.typ.n[0]
         if effects.kind == nkEffectList and effects.len == effectListLen:
@@ -767,7 +790,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
 
 proc firstOrd*(conf: ConfigRef; t: PType): Int128 =
   case t.kind
-  of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
+  of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyError:
     result = Zero
   of tySet, tyVar: result = firstOrd(conf, t.elementType)
   of tyArray: result = firstOrd(conf, t.indexType)
@@ -900,7 +923,7 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
     result = lastOrd(conf, skipModifier(t))
   of tyUserTypeClasses:
     result = lastOrd(conf, last(t))
-  of tyProxy: result = Zero
+  of tyError: result = Zero
   of tyOrdinal:
     if t.hasElementType: result = lastOrd(conf, skipModifier(t))
     else:
@@ -975,6 +998,8 @@ type
     AllowCommonBase
     PickyCAliases  # be picky about the distinction between 'cint' and 'int32'
     IgnoreFlags    # used for borrowed functions and methods; ignores the tfVarIsPtr flag
+    PickyBackendAliases # be picky about different aliases
+    IgnoreRangeShallow
 
   TTypeCmpFlags* = set[TTypeCmpFlag]
 
@@ -1203,26 +1228,40 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       inc c.recCheck
     else:
       if containsOrIncl(c, a, b): return true
+  template maybeSkipRange(x: set[TTypeKind]): set[TTypeKind] =
+    if IgnoreRangeShallow in c.flags:
+      x + {tyRange}
+    else:
+      x
+  
+  template withoutShallowFlags(body) =
+    let oldFlags = c.flags
+    c.flags.excl IgnoreRangeShallow
+    body
+    c.flags = oldFlags
 
   if x == y: return true
-  var a = skipTypes(x, {tyAlias})
+  let aliasSkipSet = maybeSkipRange({tyAlias})
+  var a = skipTypes(x, aliasSkipSet)
   while a.kind == tyUserTypeClass and tfResolved in a.flags:
-    a = skipTypes(a.last, {tyAlias})
-  var b = skipTypes(y, {tyAlias})
+    a = skipTypes(a.last, aliasSkipSet)
+  var b = skipTypes(y, aliasSkipSet)
   while b.kind == tyUserTypeClass and tfResolved in b.flags:
-    b = skipTypes(b.last, {tyAlias})
+    b = skipTypes(b.last, aliasSkipSet)
   assert(a != nil)
   assert(b != nil)
-  if a.kind != b.kind:
-    case c.cmp
-    of dcEq: return false
-    of dcEqIgnoreDistinct:
-      a = a.skipTypes({tyDistinct, tyGenericInst})
-      b = b.skipTypes({tyDistinct, tyGenericInst})
-      if a.kind != b.kind: return false
-    of dcEqOrDistinctOf:
-      a = a.skipTypes({tyDistinct, tyGenericInst})
-      if a.kind != b.kind: return false
+  case c.cmp
+  of dcEq:
+    if a.kind != b.kind: return false
+  of dcEqIgnoreDistinct:
+    let distinctSkipSet = maybeSkipRange({tyDistinct, tyGenericInst})
+    a = a.skipTypes(distinctSkipSet)
+    b = b.skipTypes(distinctSkipSet)
+    if a.kind != b.kind: return false
+  of dcEqOrDistinctOf:
+    let distinctSkipSet = maybeSkipRange({tyDistinct, tyGenericInst})
+    a = a.skipTypes(distinctSkipSet)
+    if a.kind != b.kind: return false
 
   #[
     The following code should not run in the case either side is an generic alias,
@@ -1230,14 +1269,16 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     objects ie `type A[T] = SomeObject`
   ]#
   # this is required by tunique_type but makes no sense really:
-  if x.kind == tyGenericInst and IgnoreTupleFields notin c.flags and tyDistinct != y.kind:
+  if c.cmp == dcEq and x.kind == tyGenericInst and
+      IgnoreTupleFields notin c.flags and tyDistinct != y.kind:
     let
       lhs = x.skipGenericAlias
       rhs = y.skipGenericAlias
     if rhs.kind != tyGenericInst or lhs.base != rhs.base or rhs.kidsLen != lhs.kidsLen:
       return false
-    for ff, aa in underspecifiedPairs(rhs, lhs, 1, -1):
-      if not sameTypeAux(ff, aa, c): return false
+    withoutShallowFlags:
+      for ff, aa in underspecifiedPairs(rhs, lhs, 1, -1):
+        if not sameTypeAux(ff, aa, c): return false
     return true
 
   case a.kind
@@ -1251,6 +1292,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       let symFlagsB = if b.sym != nil: b.sym.flags else: {}
       if (symFlagsA+symFlagsB) * {sfImportc, sfExportc} != {}:
         result = symFlagsA == symFlagsB
+    elif result and PickyBackendAliases in c.flags:
+      let symFlagsA = if a.sym != nil: a.sym.flags else: {}
+      let symFlagsB = if b.sym != nil: b.sym.flags else: {}
+      if (symFlagsA+symFlagsB) * {sfImportc, sfExportc} != {}:
+        result = a.id == b.id
 
   of tyStatic, tyFromExpr:
     result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
@@ -1258,9 +1304,10 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       cycleCheck()
       result = sameTypeAux(a.skipModifier, b.skipModifier, c)
   of tyObject:
-    ifFastObjectTypeCheckFailed(a, b):
-      cycleCheck()
-      result = sameObjectStructures(a, b, c) and sameFlags(a, b)
+    withoutShallowFlags:
+      ifFastObjectTypeCheckFailed(a, b):
+        cycleCheck()
+        result = sameObjectStructures(a, b, c) and sameFlags(a, b)
   of tyDistinct:
     cycleCheck()
     if c.cmp == dcEq:
@@ -1275,8 +1322,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
   of tyError:
     result = b.kind == tyError
   of tyTuple:
-    cycleCheck()
-    result = sameTuple(a, b, c) and sameFlags(a, b)
+    withoutShallowFlags:
+      cycleCheck()
+      result = sameTuple(a, b, c) and sameFlags(a, b)
   of tyTypeDesc:
     if c.cmp == dcEqIgnoreDistinct: result = false
     elif ExactTypeDescValues in c.flags:
@@ -1300,7 +1348,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
      tyAnd, tyOr, tyNot, tyAnything, tyOwned:
     cycleCheck()
     if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n
-    result = sameChildrenAux(a, b, c)
+    withoutShallowFlags:
+      result = sameChildrenAux(a, b, c)
     if result and IgnoreFlags notin c.flags:
       if IgnoreTupleFields in c.flags:
         result = a.flags * {tfVarIsPtr, tfIsOutParam} == b.flags * {tfVarIsPtr, tfIsOutParam}
@@ -1313,11 +1362,21 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
                ((ExactConstraints notin c.flags) or sameConstraints(a.n, b.n))
   of tyRange:
     cycleCheck()
-    result = sameTypeOrNilAux(a.elementType, b.elementType, c) and
-        sameValue(a.n[0], b.n[0]) and
+    result = sameTypeOrNilAux(a.elementType, b.elementType, c)
+    if result and IgnoreRangeShallow notin c.flags:
+      result = sameValue(a.n[0], b.n[0]) and
         sameValue(a.n[1], b.n[1])
-  of tyGenericInst, tyAlias, tyInferred, tyIterable:
+  of tyAlias, tyInferred, tyIterable:
+    cycleCheck()
+    result = sameTypeAux(a.skipModifier, b.skipModifier, c)
+  of tyGenericInst:
+    # BUG #23445
+    # The type system must distinguish between `T[int] = object #[empty]#`
+    # and `T[float] = object #[empty]#`!
     cycleCheck()
+    withoutShallowFlags:
+      for ff, aa in underspecifiedPairs(a, b, 1, -1):
+        if not sameTypeAux(ff, aa, c): return false
     result = sameTypeAux(a.skipModifier, b.skipModifier, c)
   of tyNone: result = false
   of tyConcept:
@@ -1329,6 +1388,19 @@ proc sameBackendType*(x, y: PType): bool =
   c.cmp = dcEqIgnoreDistinct
   result = sameTypeAux(x, y, c)
 
+proc sameBackendTypeIgnoreRange*(x, y: PType): bool =
+  var c = initSameTypeClosure()
+  c.flags.incl IgnoreTupleFields
+  c.flags.incl IgnoreRangeShallow
+  c.cmp = dcEqIgnoreDistinct
+  result = sameTypeAux(x, y, c)
+
+proc sameBackendTypePickyAliases*(x, y: PType): bool =
+  var c = initSameTypeClosure()
+  c.flags.incl {IgnoreTupleFields, PickyCAliases, PickyBackendAliases}
+  c.cmp = dcEqIgnoreDistinct
+  result = sameTypeAux(x, y, c)
+
 proc compareTypes*(x, y: PType,
                    cmp: TDistinctCompare = dcEq,
                    flags: TTypeCmpFlags = {}): bool =
@@ -1389,6 +1461,8 @@ proc commonSuperclass*(a, b: PType): PType =
       return t
     y = y.baseClass
 
+proc lacksMTypeField*(typ: PType): bool {.inline.} =
+  (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags
 
 include sizealignoffsetimpl
 
@@ -1425,6 +1499,23 @@ proc containsGenericTypeIter(t: PType, closure: RootRef): bool =
 proc containsGenericType*(t: PType): bool =
   result = iterOverType(t, containsGenericTypeIter, nil)
 
+proc containsUnresolvedTypeIter(t: PType, closure: RootRef): bool =
+  if tfUnresolved in t.flags: return true
+  case t.kind
+  of tyStatic:
+    return t.n == nil
+  of tyTypeDesc:
+    if t.base.kind == tyNone: return true
+    if containsUnresolvedTypeIter(t.base, closure): return true
+    return false
+  of tyGenericInvocation, tyGenericParam, tyFromExpr, tyAnything:
+    return true
+  else:
+    return false
+
+proc containsUnresolvedType*(t: PType): bool =
+  result = iterOverType(t, containsUnresolvedTypeIter, nil)
+
 proc baseOfDistinct*(t: PType; g: ModuleGraph; idgen: IdGenerator): PType =
   if t.kind == tyDistinct:
     result = t.elementType
@@ -1708,6 +1799,13 @@ proc processPragmaAndCallConvMismatch(msg: var string, formal, actual: PType, co
     of efTagsIllegal:
       msg.add "\n.notTag catched an illegal effect"
 
+proc typeNameAndDesc*(t: PType): string =
+  result = typeToString(t)
+  let desc = typeToString(t, preferDesc)
+  if result != desc:
+    result.add(" = ")
+    result.add(desc)
+
 proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType, n: PNode) =
   if formal.kind != tyError and actual.kind != tyError:
     let actualStr = typeToString(actual)
@@ -1837,6 +1935,3 @@ proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool =
       result = false
   else:
     result = false
-
-proc lacksMTypeField*(typ: PType): bool {.inline.} =
-  (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags
diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim
index 6b2f677a7..1711fea46 100644
--- a/compiler/varpartitions.nim
+++ b/compiler/varpartitions.nim
@@ -106,6 +106,7 @@ type
     unanalysableMutation: bool
     inAsgnSource, inConstructor, inNoSideEffectSection: int
     inConditional, inLoop: int
+    inConvHasDestructor: int
     owner: PSym
     g: ModuleGraph
 
@@ -427,16 +428,28 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) =
     # primitive literals including the empty are harmless:
     discard
 
-  of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkCast, nkConv:
+  of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkCast:
     destMightOwn(c, dest, n[1])
 
+  of nkConv:
+    if hasDestructor(n.typ):
+      inc c.inConvHasDestructor
+      destMightOwn(c, dest, n[1])
+      dec c.inConvHasDestructor
+    else:
+      destMightOwn(c, dest, n[1])
+
   of nkIfStmt, nkIfExpr:
     for i in 0..<n.len:
+      inc c.inConditional
       destMightOwn(c, dest, n[i].lastSon)
+      dec c.inConditional
 
   of nkCaseStmt:
     for i in 1..<n.len:
+      inc c.inConditional
       destMightOwn(c, dest, n[i].lastSon)
+      dec c.inConditional
 
   of nkStmtList, nkStmtListExpr:
     if n.len > 0:
@@ -481,7 +494,7 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) =
 
   of nkCallKinds:
     if n.typ != nil:
-      if hasDestructor(n.typ):
+      if hasDestructor(n.typ) or c.inConvHasDestructor > 0:
         # calls do construct, what we construct must be destroyed,
         # so dest cannot be a cursor:
         dest.flags.incl ownsData
@@ -489,8 +502,17 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) =
         # we know the result is derived from the first argument:
         var roots: seq[(PSym, int)] = @[]
         allRoots(n[1], roots, RootEscapes)
-        for r in roots:
-          connect(c, dest.sym, r[0], n[1].info)
+        if roots.len == 0 and c.inConditional > 0:
+          # when in a conditional expression,
+          # to ensure that the first argument isn't outlived
+          # by the lvalue, we need find the root, otherwise
+          # it is probably a local temporary
+          # (e.g. a return value from a call),
+          # we should prevent cursorfication
+          dest.flags.incl preventCursor
+        else:
+          for r in roots:
+            connect(c, dest.sym, r[0], n[1].info)
 
       else:
         let magic = if n[0].kind == nkSym: n[0].sym.magic else: mNone
diff --git a/compiler/vm.nim b/compiler/vm.nim
index a775cf584..161b025a6 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -507,7 +507,7 @@ proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) =
   setLen(node.sons, newLen)
   if oldLen < newLen:
     for i in oldLen..<newLen:
-      node[i] = getNullValue(typ.elementType, info, c.config)
+      node[i] = getNullValue(c, typ.elementType, info, c.config)
 
 const
   errNilAccess = "attempt to access a nil address"
@@ -609,7 +609,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcYldVal: assert false
     of opcAsgnInt:
       decodeB(rkInt)
-      regs[ra].intVal = regs[rb].intVal
+      if regs[rb].kind == rkInt:
+        regs[ra].intVal = regs[rb].intVal
+      else:
+        stackTrace(c, tos, pc, "opcAsgnInt: got " & $regs[rb].kind)
     of opcAsgnFloat:
       decodeB(rkFloat)
       regs[ra].floatVal = regs[rb].floatVal
@@ -639,6 +642,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
           regs[ra].intVal = cast[int](regs[rb].node.intVal)
         of rkNodeAddr:
           regs[ra].intVal = cast[int](regs[rb].nodeAddr)
+        of rkRegisterAddr:
+          regs[ra].intVal = cast[int](regs[rb].regAddr)
         of rkInt:
           regs[ra].intVal = regs[rb].intVal
         else:
@@ -674,16 +679,19 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       else:
         assert regs[rb].kind == rkNode
         let nb = regs[rb].node
-        case nb.kind
-        of nkCharLit..nkUInt64Lit:
-          ensureKind(rkInt)
-          regs[ra].intVal = nb.intVal
-        of nkFloatLit..nkFloat64Lit:
-          ensureKind(rkFloat)
-          regs[ra].floatVal = nb.floatVal
+        if nb == nil:
+          stackTrace(c, tos, pc, errNilAccess)
         else:
-          ensureKind(rkNode)
-          regs[ra].node = nb
+          case nb.kind
+          of nkCharLit..nkUInt64Lit:
+            ensureKind(rkInt)
+            regs[ra].intVal = nb.intVal
+          of nkFloatLit..nkFloat64Lit:
+            ensureKind(rkFloat)
+            regs[ra].floatVal = nb.floatVal
+          else:
+            ensureKind(rkNode)
+            regs[ra].node = nb
     of opcSlice:
       # A bodge, but this takes in `toOpenArray(rb, rc, rc)` and emits
       # nkTupleConstr(x, y, z) into the `regs[ra]`. These can later be used for calculating the slice we have taken.
@@ -848,25 +856,30 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcLdObj:
       # a = b.c
       decodeBC(rkNode)
-      let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[]
-      case src.kind
-      of nkEmpty..nkNilLit:
-        # for nkPtrLit, this could be supported in the future, use something like:
-        # derefPtrToReg(src.intVal + offsetof(src.typ, rc), typ_field, regs[ra], isAssign = false)
-        # where we compute the offset in bytes for field rc
-        stackTrace(c, tos, pc, errNilAccess & " " & $("kind", src.kind, "typ", typeToString(src.typ), "rc", rc))
-      of nkObjConstr:
-        let n = src[rc + 1].skipColon
-        regs[ra].node = n
-      of nkTupleConstr:
-        let n = if src.typ != nil and tfTriggersCompileTime in src.typ.flags:
-            src[rc]
-          else:
-            src[rc].skipColon
-        regs[ra].node = n
+      if rb >= regs.len or regs[rb].kind == rkNone or 
+        (regs[rb].kind == rkNode and regs[rb].node == nil) or
+        (regs[rb].kind == rkNodeAddr and regs[rb].nodeAddr[] == nil): 
+        stackTrace(c, tos, pc, errNilAccess)
       else:
-        let n = src[rc]
-        regs[ra].node = n
+        let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[]
+        case src.kind
+        of nkEmpty..nkNilLit:
+          # for nkPtrLit, this could be supported in the future, use something like:
+          # derefPtrToReg(src.intVal + offsetof(src.typ, rc), typ_field, regs[ra], isAssign = false)
+          # where we compute the offset in bytes for field rc
+          stackTrace(c, tos, pc, errNilAccess & " " & $("kind", src.kind, "typ", typeToString(src.typ), "rc", rc))
+        of nkObjConstr:
+          let n = src[rc + 1].skipColon
+          regs[ra].node = n
+        of nkTupleConstr:
+          let n = if src.typ != nil and tfTriggersCompileTime in src.typ.flags:
+              src[rc]
+            else:
+              src[rc].skipColon
+          regs[ra].node = n
+        else:
+          let n = src[rc]
+          regs[ra].node = n
     of opcLdObjAddr:
       # a = addr(b.c)
       decodeBC(rkNodeAddr)
@@ -892,8 +905,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         stackTrace(c, tos, pc, errNilAccess)
       elif dest[shiftedRb].kind == nkExprColonExpr:
         writeField(dest[shiftedRb][1], regs[rc])
+        dest[shiftedRb][1].flags.incl nfSkipFieldChecking
       else:
         writeField(dest[shiftedRb], regs[rc])
+        dest[shiftedRb].flags.incl nfSkipFieldChecking
     of opcWrStrIdx:
       decodeBC(rkNode)
       let idx = regs[rb].intVal.int
@@ -1361,7 +1376,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         else:
           internalError(c.config, c.debug[pc], "opcParseFloat: Incorrectly created openarray")
       else:
-        regs[ra].intVal = parseBiggestFloat(regs[ra].node.strVal, rcAddr.floatVal)
+        regs[ra].intVal = parseBiggestFloat(regs[rb].node.strVal, rcAddr.floatVal)
 
     of opcRangeChck:
       let rb = instr.regB
@@ -1376,7 +1391,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let rb = instr.regB
       let rc = instr.regC
       let bb = regs[rb].node
+      if bb.kind == nkNilLit:
+        stackTrace(c, tos, pc, "attempt to call nil closure")
       let isClosure = bb.kind == nkTupleConstr
+      if isClosure and bb[0].kind == nkNilLit:
+        stackTrace(c, tos, pc, "attempt to call nil closure")
       let prc = if not isClosure: bb.sym else: bb[0].sym
       if prc.offset < -1:
         # it's a callback:
@@ -1416,7 +1435,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
         newSeq(newFrame.slots, prc.offset+ord(isClosure))
         if not isEmptyType(prc.typ.returnType):
-          putIntoReg(newFrame.slots[0], getNullValue(prc.typ.returnType, prc.info, c.config))
+          putIntoReg(newFrame.slots[0], getNullValue(c, prc.typ.returnType, prc.info, c.config))
         for i in 1..rc-1:
           newFrame.slots[i] = regs[rb+i]
         if isClosure:
@@ -1549,7 +1568,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNew:
       ensureKind(rkNode)
       let typ = c.types[instr.regBx - wordExcess]
-      regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
+      regs[ra].node = getNullValue(c, typ, c.debug[pc], c.config)
       regs[ra].node.flags.incl nfIsRef
     of opcNewSeq:
       let typ = c.types[instr.regBx - wordExcess]
@@ -1561,7 +1580,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       regs[ra].node.typ = typ
       newSeq(regs[ra].node.sons, count)
       for i in 0..<count:
-        regs[ra].node[i] = getNullValue(typ.elementType, c.debug[pc], c.config)
+        regs[ra].node[i] = getNullValue(c, typ.elementType, c.debug[pc], c.config)
     of opcNewStr:
       decodeB(rkNode)
       regs[ra].node = newNodeI(nkStrLit, c.debug[pc])
@@ -1573,7 +1592,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcLdNull:
       ensureKind(rkNode)
       let typ = c.types[instr.regBx - wordExcess]
-      regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
+      regs[ra].node = getNullValue(c, typ, c.debug[pc], c.config)
       # opcLdNull really is the gist of the VM's problems: should it load
       # a fresh null to  regs[ra].node  or to regs[ra].node[]? This really
       # depends on whether regs[ra] represents the variable itself or whether
@@ -2302,7 +2321,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
 
       # setup parameters:
       if not isEmptyType(sym.typ.returnType) or sym.kind == skMacro:
-        putIntoReg(tos.slots[0], getNullValue(sym.typ.returnType, sym.info, c.config))
+        putIntoReg(tos.slots[0], getNullValue(c, sym.typ.returnType, sym.info, c.config))
       # XXX We could perform some type checking here.
       for i in 0..<sym.typ.paramsLen:
         putIntoReg(tos.slots[i+1], args[i])
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index e293ab7b2..294aaaa79 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -237,7 +237,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   of tySequence: result = mapTypeToBracket("seq", mSeq, t, info)
   of tyProc:
     if inst:
-      result = newNodeX(nkProcTy)
+      result = newNodeX(if tfIterator in t.flags: nkIteratorTy else: nkProcTy)
       var fp = newNodeX(nkFormalParams)
       if t.returnType == nil:
         fp.add newNodeI(nkEmpty, info)
@@ -246,8 +246,15 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
       for i in FirstParamAt..<t.kidsLen:
         fp.add newIdentDefs(t.n[i], t[i])
       result.add fp
-      result.add if t.n[0].len > 0: t.n[0][pragmasEffects].copyTree
-                 else: newNodeI(nkEmpty, info)
+      var prag =
+        if t.n[0].len > 0:
+          t.n[0][pragmasEffects].copyTree
+        else:
+          newNodeI(nkEmpty, info)
+      if t.callConv != ccClosure or tfExplicitCallConv in t.flags:
+        if prag.kind == nkEmpty: prag = newNodeI(nkPragma, info)
+        prag.add newIdentNode(getIdent(cache, $t.callConv), info)
+      result.add prag
     else:
       result = mapTypeToBracket("proc", mNone, t, info)
   of tyOpenArray: result = mapTypeToBracket("openArray", mOpenArray, t, info)
@@ -282,7 +289,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   of tyUInt32: result = atomicType("uint32", mUInt32)
   of tyUInt64: result = atomicType("uint64", mUInt64)
   of tyVarargs: result = mapTypeToBracket("varargs", mVarargs, t, info)
-  of tyProxy: result = atomicType("error", mNone)
+  of tyError: result = atomicType("error", mNone)
   of tyBuiltInTypeClass:
     result = mapTypeToBracket("builtinTypeClass", mNone, t, info)
   of tyUserTypeClass, tyUserTypeClassInst:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 366fc7b29..0c7a49984 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -53,6 +53,7 @@ type
     gfNode # Affects how variables are loaded - always loads as rkNode
     gfNodeAddr # Affects how variables are loaded - always loads as rkNodeAddr
     gfIsParam # do not deepcopy parameters, they are immutable
+    gfIsSinkParam # deepcopy sink parameters
   TGenFlags = set[TGenFlag]
 
 proc debugInfo(c: PCtx; info: TLineInfo): string =
@@ -245,7 +246,7 @@ proc getTemp(cc: PCtx; tt: PType): TRegister =
 
 proc freeTemp(c: PCtx; r: TRegister) =
   let c = c.prc
-  if c.regInfo[r].kind in {slotSomeTemp..slotTempComplex}:
+  if r < c.regInfo.len and c.regInfo[r].kind in {slotSomeTemp..slotTempComplex}:
     # this seems to cause https://github.com/nim-lang/Nim/issues/10647
     c.regInfo[r].inUse = false
 
@@ -357,12 +358,13 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
     #if c.prc.regInfo[i].kind in {slotFixedVar, slotFixedLet}:
     if i != dest:
       when not defined(release):
-        if c.prc.regInfo[i].inUse and c.prc.regInfo[i].kind in {slotTempUnknown,
-                                  slotTempInt,
-                                  slotTempFloat,
-                                  slotTempStr,
-                                  slotTempComplex}:
-          raiseAssert "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind
+        if c.config.cmd != cmdCheck:
+          if c.prc.regInfo[i].inUse and c.prc.regInfo[i].kind in {slotTempUnknown,
+                                    slotTempInt,
+                                    slotTempFloat,
+                                    slotTempStr,
+                                    slotTempComplex}:
+            raiseAssert "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind
       c.prc.regInfo[i] = (inUse: false, kind: slotEmpty)
 
   c.clearDest(n, dest)
@@ -619,10 +621,17 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
   let fntyp = skipTypes(n[0].typ, abstractInst)
   for i in 0..<n.len:
     var r: TRegister = x+i
-    c.gen(n[i], r, {gfIsParam})
     if i >= fntyp.signatureLen:
+      c.gen(n[i], r, {gfIsParam})
       internalAssert c.config, tfVarargs in fntyp.flags
       c.gABx(n, opcSetType, r, c.genType(n[i].typ))
+    else:
+      if fntyp[i] != nil and fntyp[i].kind == tySink and
+          fntyp[i].skipTypes({tySink}).kind in {tyObject, tyString, tySequence}:
+        c.gen(n[i], r, {gfIsSinkParam})
+      else:
+        c.gen(n[i], r, {gfIsParam})
+
   if dest < 0:
     c.gABC(n, opcIndCall, 0, x, n.len)
   else:
@@ -696,6 +705,9 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
       let dest = c.genx(le, {gfNodeAddr})
       c.gABC(le, opcWrDeref, dest, 0, value)
       c.freeTemp(dest)
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    if sameBackendType(le.typ, le[1].typ):
+      genAsgnPatch(c, le[1], value)
   else:
     discard
 
@@ -868,7 +880,7 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
     genBinaryABC(c, n, dest, opc)
   c.genNarrow(n, dest)
 
-proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
+proc genConv(c: PCtx; n, arg: PNode; dest: var TDest, flags: TGenFlags = {}; opc=opcConv) =
   let t2 = n.typ.skipTypes({tyDistinct})
   let targ2 = arg.typ.skipTypes({tyDistinct})
 
@@ -882,7 +894,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
       result = false
 
   if implicitConv():
-    gen(c, arg, dest)
+    gen(c, arg, dest, flags)
     return
 
   let tmp = c.genx(arg)
@@ -900,9 +912,15 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
   c.freeTemp(tmp)
 
 proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
+  template isSigned(typ: PType): bool {.dirty.} =
+    typ.kind == tyEnum and firstOrd(c.config, typ) < 0 or
+    typ.kind in {tyInt..tyInt64}
+  template isUnsigned(typ: PType): bool {.dirty.} =
+    typ.kind == tyEnum and firstOrd(c.config, typ) >= 0 or
+    typ.kind in {tyUInt..tyUInt64, tyChar, tyBool}
+
   const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar, tyEnum, tyBool}
-  var signedIntegers = {tyInt..tyInt64}
-  var unsignedIntegers = {tyUInt..tyUInt64, tyChar, tyEnum, tyBool}
+
   let src = n[1].typ.skipTypes(abstractRange)#.kind
   let dst = n[0].typ.skipTypes(abstractRange)#.kind
   let srcSize = getSize(c.config, src)
@@ -914,12 +932,12 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
     if dest < 0: dest = c.getTemp(n[0].typ)
     c.gABC(n, opcAsgnInt, dest, tmp)
     if dstSize != sizeof(BiggestInt): # don't do anything on biggest int types
-      if dst.kind in signedIntegers: # we need to do sign extensions
+      if isSigned(dst): # we need to do sign extensions
         if dstSize <= srcSize:
           # Sign extension can be omitted when the size increases.
           c.gABC(n, opcSignExtend, dest, TRegister(dstSize*8))
-      elif dst.kind in unsignedIntegers:
-        if src.kind in signedIntegers or dstSize < srcSize:
+      elif isUnsigned(dst):
+        if isSigned(src) or dstSize < srcSize:
           # Cast from signed to unsigned always needs narrowing. Cast
           # from unsigned to unsigned only needs narrowing when target
           # is smaller than source.
@@ -947,7 +965,7 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
     if dest < 0: dest = c.getTemp(n[0].typ)
     if src.kind == tyFloat32:
       c.gABC(n, opcCastFloatToInt32, dest, tmp)
-      if dst.kind in unsignedIntegers:
+      if isUnsigned(dst):
         # integers are sign extended by default.
         # since there is no opcCastFloatToUInt32, narrowing should do the trick.
         c.gABC(n, opcNarrowU, dest, TRegister(32))
@@ -1044,7 +1062,7 @@ proc whichAsgnOpc(n: PNode; requiresCopy = true): TOpcode =
   else:
     (if requiresCopy: opcAsgnComplex else: opcFastAsgnComplex)
 
-proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
+proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMagic) =
   case m
   of mAnd: c.genAndOr(n, opcFJmp, dest)
   of mOr:  c.genAndOr(n, opcTJmp, dest)
@@ -1183,7 +1201,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
       c.gABC(n, opcNarrowU, dest, TRegister(size*8))
   of mCharToStr, mBoolToStr, mCStrToStr, mStrToStr, mEnumToStr:
-    genConv(c, n, n[1], dest)
+    genConv(c, n, n[1], dest, flags)
   of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
   of mEqCString: genBinaryABC(c, n, dest, opcEqCString)
   of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
@@ -1229,13 +1247,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.freeTemp(tmp1)
     c.genAsgnPatch(d2AsNode, d2)
     c.freeTemp(d2)
-  of mReset:
-    unused(c, n, dest)
-    var d = c.genx(n[1])
-    # XXX use ldNullOpcode() here?
-    c.gABx(n, opcLdNull, d, c.genType(n[1].typ))
-    c.gABC(n, opcNodeToReg, d, d)
-    c.genAsgnPatch(n[1], d)
   of mDefault, mZeroDefault:
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABx(n, ldNullOpcode(n.typ), dest, c.genType(n.typ))
@@ -1530,7 +1541,11 @@ proc setSlot(c: PCtx; v: PSym) =
   if v.position == 0:
     v.position = getFreeRegister(c, if v.kind == skLet: slotFixedLet else: slotFixedVar, start = 1)
 
-proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
+template cannotEval(c: PCtx; n: PNode) =
+  if c.config.cmd == cmdCheck:
+    localError(c.config, n.info, "cannot evaluate at compile time: " & 
+    n.renderTree)
+    return
   globalError(c.config, n.info, "cannot evaluate at compile time: " &
     n.renderTree)
 
@@ -1653,6 +1668,9 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
         c.freeTemp(cc)
       else:
         gen(c, ri, dest)
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    if sameBackendType(le.typ, le[1].typ):
+      genAsgn(c, le[1], ri, requiresCopy)
   else:
     let dest = c.genx(le, {gfNodeAddr})
     genAsgn(c, dest, ri, requiresCopy)
@@ -1691,10 +1709,10 @@ proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
     localError(c.config, info,
                "cannot 'importc' variable at compile time; " & s.name.s)
 
-proc getNullValue*(typ: PType, info: TLineInfo; conf: ConfigRef): PNode
+proc getNullValue*(c: PCtx; typ: PType, info: TLineInfo; conf: ConfigRef): PNode
 
 proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
-  c.globals.add(getNullValue(s.typ, n.info, c.config))
+  c.globals.add(getNullValue(c, s.typ, n.info, c.config))
   s.position = c.globals.len
   # This is rather hard to support, due to the laziness of the VM code
   # generator. See tests/compile/tmacro2 for why this is necessary:
@@ -1730,6 +1748,8 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
         c.gABx(n, opcLdGlobalAddr, dest, s.position)
     elif isImportcVar:
       c.gABx(n, opcLdGlobalDerefFFI, dest, s.position)
+    elif gfIsSinkParam in flags:
+      genAsgn(c, dest, n, requiresCopy = true)
     elif fitsRegister(s.typ) and gfNode notin flags:
       var cc = c.getTemp(n.typ)
       c.gABx(n, opcLdGlobal, cc, s.position)
@@ -1743,7 +1763,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
                           s.kind in {skParam, skResult}):
       if dest < 0:
         dest = s.position + ord(s.kind == skParam)
-        internalAssert(c.config, c.prc.regInfo[dest].kind < slotSomeTemp)
+        internalAssert(c.config, c.prc.regInfo.len > dest and c.prc.regInfo[dest].kind < slotSomeTemp)
       else:
         # we need to generate an assignment:
         let requiresCopy = c.prc.regInfo[dest].kind >= slotSomeTemp and
@@ -1873,21 +1893,21 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
     let opc = if gfNodeAddr in flags: opcLdArrAddr else: opcLdArr
     genArrAccessOpcode(c, n, dest, opc, flags)
 
-proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) =
+proc getNullValueAux(c: PCtx; t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) =
   if t != nil and t.baseClass != nil:
     let b = skipTypes(t.baseClass, skipPtrs)
-    getNullValueAux(b, b.n, result, conf, currPosition)
+    getNullValueAux(c, b, b.n, result, conf, currPosition)
   case obj.kind
   of nkRecList:
-    for i in 0..<obj.len: getNullValueAux(nil, obj[i], result, conf, currPosition)
+    for i in 0..<obj.len: getNullValueAux(c, nil, obj[i], result, conf, currPosition)
   of nkRecCase:
-    getNullValueAux(nil, obj[0], result, conf, currPosition)
+    getNullValueAux(c, nil, obj[0], result, conf, currPosition)
     for i in 1..<obj.len:
-      getNullValueAux(nil, lastSon(obj[i]), result, conf, currPosition)
+      getNullValueAux(c, nil, lastSon(obj[i]), result, conf, currPosition)
   of nkSym:
     let field = newNodeI(nkExprColonExpr, result.info)
     field.add(obj)
-    let value = getNullValue(obj.sym.typ, result.info, conf)
+    let value = getNullValue(c, obj.sym.typ, result.info, conf)
     value.flags.incl nfSkipFieldChecking
     field.add(value)
     result.add field
@@ -1895,7 +1915,7 @@ proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currP
     inc currPosition
   else: globalError(conf, result.info, "cannot create null element for: " & $obj)
 
-proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
+proc getNullValue(c: PCtx; typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
   var t = skipTypes(typ, abstractRange+{tyStatic, tyOwned}-{tyTypeDesc})
   case t.kind
   of tyBool, tyEnum, tyChar, tyInt..tyInt64:
@@ -1915,22 +1935,22 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
       result = newNodeIT(nkNilLit, info, t)
     else:
       result = newNodeIT(nkTupleConstr, info, t)
-      result.add(newNodeIT(nkNilLit, info, t))
-      result.add(newNodeIT(nkNilLit, info, t))
+      result.add(newNodeIT(nkNilLit, info, getSysType(c.graph, info, tyPointer)))
+      result.add(newNodeIT(nkNilLit, info, getSysType(c.graph, info, tyPointer)))
   of tyObject:
     result = newNodeIT(nkObjConstr, info, t)
     result.add(newNodeIT(nkEmpty, info, t))
     # initialize inherited fields, and all in the correct order:
     var currPosition = 0
-    getNullValueAux(t, t.n, result, conf, currPosition)
+    getNullValueAux(c, t, t.n, result, conf, currPosition)
   of tyArray:
     result = newNodeIT(nkBracket, info, t)
     for i in 0..<toInt(lengthOrd(conf, t)):
-      result.add getNullValue(elemType(t), info, conf)
+      result.add getNullValue(c, elemType(t), info, conf)
   of tyTuple:
     result = newNodeIT(nkTupleConstr, info, t)
     for a in t.kids:
-      result.add getNullValue(a, info, conf)
+      result.add getNullValue(c, a, info, conf)
   of tySet:
     result = newNodeIT(nkCurly, info, t)
   of tySequence, tyOpenArray:
@@ -1958,7 +1978,7 @@ proc genVarSection(c: PCtx; n: PNode) =
         if s.position == 0:
           if importcCond(c, s): c.importcSym(a.info, s)
           else:
-            let sa = getNullValue(s.typ, a.info, c.config)
+            let sa = getNullValue(c, s.typ, a.info, c.config)
             #if s.ast.isNil: getNullValue(s.typ, a.info)
             #else: s.ast
             assert sa.kind != nkCall
@@ -1980,7 +2000,7 @@ proc genVarSection(c: PCtx; n: PNode) =
           # the problem is that closure types are tuples in VM, but the types of its children
           # shouldn't have the same type as closure types.
           let tmp = c.genx(a[0], {gfNodeAddr})
-          let sa = getNullValue(s.typ, a.info, c.config)
+          let sa = getNullValue(c, s.typ, a.info, c.config)
           let val = c.genx(sa)
           c.genAdditionalCopy(sa, opcWrDeref, tmp, 0, val)
           c.freeTemp(val)
@@ -2165,7 +2185,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     if n[0].kind == nkSym:
       let s = n[0].sym
       if s.magic != mNone:
-        genMagic(c, n, dest, s.magic)
+        genMagic(c, n, dest, flags, s.magic)
       elif s.kind == skMethod:
         localError(c.config, n.info, "cannot call method " & s.name.s &
           " at compile time")
@@ -2183,7 +2203,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
       genLit(c, n, dest)
   of nkUIntLit..pred(nkNilLit): genLit(c, n, dest)
   of nkNilLit:
-    if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info, c.config), dest)
+    if not n.typ.isEmptyType: genLit(c, getNullValue(c, n.typ, n.info, c.config), dest)
     else: unused(c, n, dest)
   of nkAsgn, nkFastAsgn, nkSinkAsgn:
     unused(c, n, dest)
@@ -2222,11 +2242,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     unused(c, n, dest)
     gen(c, n[0])
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    genConv(c, n, n[1], dest)
+    genConv(c, n, n[1], dest, flags)
   of nkObjDownConv:
-    genConv(c, n, n[0], dest)
+    genConv(c, n, n[0], dest, flags)
   of nkObjUpConv:
-    genConv(c, n, n[0], dest)
+    genConv(c, n, n[0], dest, flags)
   of nkVarSection, nkLetSection:
     unused(c, n, dest)
     genVarSection(c, n)
@@ -2235,18 +2255,21 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     #discard genProc(c, s)
     genLit(c, newSymNode(n[namePos].sym), dest)
   of nkChckRangeF, nkChckRange64, nkChckRange:
-    let
-      tmp0 = c.genx(n[0])
-      tmp1 = c.genx(n[1])
-      tmp2 = c.genx(n[2])
-    c.gABC(n, opcRangeChck, tmp0, tmp1, tmp2)
-    c.freeTemp(tmp1)
-    c.freeTemp(tmp2)
-    if dest >= 0:
-      gABC(c, n, whichAsgnOpc(n), dest, tmp0)
-      c.freeTemp(tmp0)
+    if skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64}:
+      genConv(c, n, n[0], dest, flags)
     else:
-      dest = tmp0
+      let
+        tmp0 = c.genx(n[0])
+        tmp1 = c.genx(n[1])
+        tmp2 = c.genx(n[2])
+      c.gABC(n, opcRangeChck, tmp0, tmp1, tmp2)
+      c.freeTemp(tmp1)
+      c.freeTemp(tmp2)
+      if dest >= 0:
+        gABC(c, n, whichAsgnOpc(n), dest, tmp0)
+        c.freeTemp(tmp0)
+      else:
+        dest = tmp0
   of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
      nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt,
      nkMixinStmt, nkBindStmt, declarativeDefs, nkMacroDef:
@@ -2259,7 +2282,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
   of nkPar, nkClosure, nkTupleConstr: genTupleConstr(c, n, dest)
   of nkCast:
     if allowCast in c.features:
-      genConv(c, n, n[1], dest, opcCast)
+      genConv(c, n, n[1], dest, flags, opcCast)
     else:
       genCastIntFloat(c, n, dest)
   of nkTypeOfExpr:
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index 23b41fd2e..45194e633 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -27,6 +27,7 @@ from std/envvars import getEnv, existsEnv, delEnv, putEnv, envPairs
 from std/os import getAppFilename
 from std/private/oscommon import dirExists, fileExists
 from std/private/osdirs import walkDir, createDir
+from std/private/ospaths2 import getCurrentDir
 
 from std/times import cpuTime
 from std/hashes import hash
@@ -341,8 +342,8 @@ proc registerAdditionalOps*(c: PCtx) =
     ## reproducible builds and users need to understand that this runs at CT.
     ## Note that `staticExec` can already do equal amount of damage so it's more
     ## of a semantic issue than a security issue.
-    registerCallback c, "stdlib.os.getCurrentDir", proc (a: VmArgs) {.nimcall.} =
-      setResult(a, os.getCurrentDir())
+    registerCallback c, "stdlib.ospaths2.getCurrentDir", proc (a: VmArgs) {.nimcall.} =
+      setResult(a, getCurrentDir())
     registerCallback c, "stdlib.osproc.execCmdEx", proc (a: VmArgs) {.nimcall.} =
       let options = getNode(a, 1).fromLit(set[osproc.ProcessOption])
       a.setResult osproc.execCmdEx(getString(a, 0), options).toLit
diff --git a/config/config.nims b/config/config.nims
index 4b8582d9c..b8979e8e3 100644
--- a/config/config.nims
+++ b/config/config.nims
@@ -20,4 +20,4 @@ when defined(nimStrictMode):
     switch("hintAsError", "ConvFromXtoItselfNotNeeded")
     # future work: XDeclaredButNotUsed
 
-switch("define", "nimVersion:" & NimVersion)
+switch("define", "nimVersion:" & NimVersion) # deadcode
diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg
index 5b902b362..99751f79d 100644
--- a/config/nimdoc.cfg
+++ b/config/nimdoc.cfg
@@ -232,6 +232,10 @@ doc.file = """<?xml version="1.0" encoding="utf-8" ?>
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>$title</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -255,9 +259,6 @@ doc.file = """<?xml version="1.0" encoding="utf-8" ?>
     </div>
   </div>
   $analytics
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
 """
diff --git a/doc/manual.md b/doc/manual.md
index 3b402e9f4..5c36a0a7b 100644
--- a/doc/manual.md
+++ b/doc/manual.md
@@ -3220,6 +3220,15 @@ A const section declares constants whose values are constant expressions:
 
 Once declared, a constant's symbol can be used as a constant expression.
 
+The value part of a constant declaration opens a new scope for each constant,
+so no symbols declared in the constant value are accessible outside of it.
+
+  ```nim
+  const foo = (var a = 1; a)
+  const bar = a # error
+  let baz = a # error
+  ```
+
 See [Constants and Constant Expressions] for details.
 
 Static statement/expression
@@ -3788,9 +3797,6 @@ type conversions to unsigned integers and between unsigned integers. The
 rationale for this is mostly better interoperability with the C Programming
 language when algorithms are ported from C to Nim.
 
-Exception: Values that are converted to an unsigned type at compile time
-are checked so that code like `byte(-1)` does not compile.
-
 **Note**: Historically the operations
 were unchecked and the conversions were sometimes checked but starting with
 the revision 1.0.4 of this document and the language implementation the
@@ -4457,7 +4463,42 @@ as an example:
 Overloading of the subscript operator
 -------------------------------------
 
-The `[]` subscript operator for arrays/openarrays/sequences can be overloaded.
+The `[]` subscript operator for arrays/openarrays/sequences can be overloaded
+for any type (with some exceptions) by defining a routine with the name `[]`.
+
+  ```nim
+  type Foo = object
+    data: seq[int]
+  
+  proc `[]`(foo: Foo, i: int): int =
+    result = foo.data[i]
+  
+  let foo = Foo(data: @[1, 2, 3])
+  echo foo[1] # 2
+  ```
+
+Assignment to subscripts can also be overloaded by naming a routine `[]=`,
+which has precedence over assigning to the result of `[]`.
+
+  ```nim
+  type Foo = object
+    data: seq[int]
+  
+  proc `[]`(foo: Foo, i: int): int =
+    result = foo.data[i]
+  proc `[]=`(foo: var Foo, i: int, val: int) =
+    foo.data[i] = val
+  
+  var foo = Foo(data: @[1, 2, 3])
+  echo foo[1] # 2
+  foo[1] = 5
+  echo foo.data # @[1, 5, 3]
+  echo foo[1] # 5
+  ```
+
+Overloads of the subscript operator cannot be applied to routine or type
+symbols themselves, as this conflicts with the syntax for instantiating
+generic parameters, i.e. `foo[int](1, 2, 3)` or `Foo[int]`.
 
 
 Methods
@@ -5419,6 +5460,8 @@ To override the compiler's side effect analysis a `{.noSideEffect.}`
 **Side effects are usually inferred. The inference for side effects is
 analogous to the inference for exception tracking.**
 
+When the compiler cannot infer side effects, as is the case for imported
+functions, one can annotate them with the `sideEffect` pragma.
 
 GC safety effect
 ----------------
@@ -6214,9 +6257,12 @@ scope is controlled by the `inject`:idx: and `gensym`:idx: pragmas:
 `gensym`'ed symbols are not exposed but `inject`'ed symbols are.
 
 The default for symbols of entity `type`, `var`, `let` and `const`
-is `gensym` and for `proc`, `iterator`, `converter`, `template`,
-`macro` is `inject`. However, if the name of the entity is passed as a
-template parameter, it is an `inject`'ed symbol:
+is `gensym`. For `proc`, `iterator`, `converter`, `template`,
+`macro`, the default is `inject`, but if a `gensym` symbol with the same name
+is defined in the same syntax-level scope, it will be `gensym` by default.
+This can be overriden by marking the routine as `inject`. 
+
+If the name of the entity is passed as a template parameter, it is an `inject`'ed symbol:
 
   ```nim
   template withFile(f, fn, mode: untyped, actions: untyped): untyped =
@@ -8701,7 +8747,7 @@ after the last specified parameter. Nim string values will be converted to C
 strings automatically:
 
   ```Nim
-  proc printf(formatstr: cstring) {.nodecl, varargs.}
+  proc printf(formatstr: cstring) {.header: "<stdio.h>", varargs.}
 
   printf("hallo %s", "world") # "world" will be passed as C string
   ```
diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md
index 9b52fbd2a..da51d59ad 100644
--- a/doc/manual_experimental.md
+++ b/doc/manual_experimental.md
@@ -2522,31 +2522,39 @@ Notice we use the overload of `()` to have the same semantics in Nim, but on the
 This allows to easy interop with functions that accepts for example a `const` operator in its signature. 
 
 
-Injected symbols in generic procs
-=================================
-
-With the experimental option `genericsOpenSym`, captured symbols in generic
-routine bodies may be replaced by symbols injected locally by templates/macros
-at instantiation time. `bind` may be used to keep the captured symbols over
-the injected ones regardless of enabling the option.
-  
+Injected symbols in generic procs and templates
+===============================================
+
+With the experimental option `openSym`, captured symbols in generic routine and
+template bodies may be replaced by symbols injected locally by templates/macros
+at instantiation time. `bind` may be used to keep the captured symbols over the
+injected ones regardless of enabling the options, but other methods like
+renaming the captured symbols should be used instead so that the code is not
+affected by context changes.
+
 Since this change may affect runtime behavior, the experimental switch
-`genericsOpenSym` needs to be enabled, and a warning is given in the case
-where an injected symbol would replace a captured symbol not bound by `bind`
-and the experimental switch isn't enabled.
+`openSym` needs to be enabled; and a warning is given in the case where an
+injected symbol would replace a captured symbol not bound by `bind` and
+the experimental switch isn't enabled.
 
 ```nim
 const value = "captured"
-template foo(x: int, body: untyped) =
+template foo(x: int, body: untyped): untyped =
   let value {.inject.} = "injected"
   body
 
 proc old[T](): string =
   foo(123):
-    return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:genericsOpenSym`
+    return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
 echo old[int]() # "captured"
 
-{.experimental: "genericsOpenSym".}
+template oldTempl(): string =
+  block:
+    foo(123):
+      value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
+echo oldTempl() # "captured"
+
+{.experimental: "openSym".}
 
 proc bar[T](): string =
   foo(123):
@@ -2558,6 +2566,53 @@ proc baz[T](): string =
   foo(123):
     return value
 assert baz[int]() == "captured"
+
+template barTempl(): string =
+  block:
+    foo(123):
+      value
+assert barTempl() == "injected" # previously it would be "captured"
+
+template bazTempl(): string =
+  bind value
+  block:
+    foo(123):
+      value
+assert bazTempl() == "captured"
+```
+
+This option also generates a new node kind `nnkOpenSym` which contains
+exactly 1 `nnkSym` node. In the future this might be merged with a slightly
+modified `nnkOpenSymChoice` node but macros that want to support the
+experimental feature should still handle `nnkOpenSym`, as the node kind would
+simply not be generated as opposed to being removed.
+
+Another experimental switch `genericsOpenSym` exists that enables this behavior
+at instantiation time, meaning templates etc can enable it specifically when
+they are being called. However this does not generate `nnkOpenSym` nodes
+(unless the other switch is enabled) and so doesn't reflect the regular
+behavior of the switch.
+
+```nim
+const value = "captured"
+template foo(x: int, body: untyped): untyped =
+  let value {.inject.} = "injected"
+  {.push experimental: "genericsOpenSym".}
+  body
+  {.pop.}
+
+proc bar[T](): string =
+  foo(123):
+    return value
+echo bar[int]() # "injected"
+
+template barTempl(): string =
+  block:
+    var res: string
+    foo(123):
+      res = value
+    res
+assert barTempl() == "injected"
 ```
 
 
diff --git a/doc/nimc.md b/doc/nimc.md
index 25acf31e8..38558454b 100644
--- a/doc/nimc.md
+++ b/doc/nimc.md
@@ -481,6 +481,28 @@ They are:
 5. nl_types. No headers for this.
 6. As mmap is not supported, the nimAllocPagesViaMalloc option has to be used.
 
+GPU Compilation
+===============
+
+Compiling for GPU computation can be achieved with `--cc:nvcc` for CUDA with nvcc, or with `--cc:hipcc` for AMD GPUs with HIP. Both compilers require building for C++ with `nim cpp`.
+
+Here's a very simple CUDA kernel example using emit, which can be compiled with `nim cpp --cc:nvcc --define:"useMalloc" hello_kernel.nim` assuming you have the CUDA toolkit installed.
+
+```nim
+{.emit: """
+__global__ void add(int a, int b) {
+  int c;
+  c = a + b;
+}
+""".}
+
+proc main() =
+  {.emit: """
+  add<<<1,1>>>(2,7);
+  """.}
+
+main()
+```
 
 DLL generation
 ==============
diff --git a/doc/nimdoc.css b/doc/nimdoc.css
index a9e4ac9c6..0c399e4c1 100644
--- a/doc/nimdoc.css
+++ b/doc/nimdoc.css
@@ -623,8 +623,8 @@ pre {
 

 table.line-nums-table {

   border-radius: 4px;

-  border: 1px solid #cccccc;

-  background-color: ghostwhite;

+  border: 1px solid var(--border);

+  background-color: var(--secondary-background);

   border-collapse: separate;

   margin-top: 15px;

   margin-bottom: 25px; }

@@ -660,6 +660,9 @@ table {
   border-collapse: collapse;

   border-color: var(--third-background);

   border-spacing: 0;

+}

+

+table:not(.line-nums-table) {

   font-size: 0.9em;

 }

 

@@ -678,7 +681,7 @@ table th.docinfo-name {
   text-align: right;

 }

 

-table tr:hover {

+table:not(.line-nums-table) tr:hover {

   background-color: var(--third-background); }

 

 

diff --git a/doc/nims.md b/doc/nims.md
index 42cc6e124..987cc2096 100644
--- a/doc/nims.md
+++ b/doc/nims.md
@@ -61,43 +61,44 @@ Standard library modules
 
 At least the following standard library modules are available:
 
-* [macros](macros.html)
-* [os](os.html)
-* [strutils](strutils.html)
-* [math](math.html)
-* [distros](distros.html)
-* [sugar](sugar.html)
 * [algorithm](algorithm.html)
 * [base64](base64.html)
 * [bitops](bitops.html)
 * [chains](chains.html)
 * [colors](colors.html)
 * [complex](complex.html)
+* [distros](distros.html)
+* [std/editdistance](editdistance.html)
 * [htmlgen](htmlgen.html)
+* [htmlparser](htmlparser.html)
 * [httpcore](httpcore.html)
+* [json](json.html)
 * [lenientops](lenientops.html)
+* [macros](macros.html)
+* [math](math.html)
 * [options](options.html)
+* [os](os.html)
+* [parsecfg](parsecfg.html)
+* [parsecsv](parsecsv.html)
+* [parsejson](parsejson.html)
+* [parsesql](parsesql.html)
 * [parseutils](parseutils.html)
 * [punycode](punycode.html)
 * [random](random.html)
+* [ropes](ropes.html)
+* [std/setutils](setutils.html)
 * [stats](stats.html)
 * [strformat](strformat.html)
 * [strmisc](strmisc.html)
 * [strscans](strscans.html)
+* [strtabs](strtabs.html)
+* [strutils](strutils.html)
+* [sugar](sugar.html)
 * [unicode](unicode.html)
+* [unidecode](unidecode.html)
 * [uri](uri.html)
-* [std/editdistance](editdistance.html)
 * [std/wordwrap](wordwrap.html)
-* [parsecsv](parsecsv.html)
-* [parsecfg](parsecfg.html)
-* [parsesql](parsesql.html)
 * [xmlparser](xmlparser.html)
-* [htmlparser](htmlparser.html)
-* [ropes](ropes.html)
-* [json](json.html)
-* [parsejson](parsejson.html)
-* [strtabs](strtabs.html)
-* [unidecode](unidecode.html)
 
 In addition to the standard Nim syntax ([system](system.html) module),
 NimScripts support the procs and templates defined in the
diff --git a/doc/tut2.md b/doc/tut2.md
index 4b9049082..1b59288d5 100644
--- a/doc/tut2.md
+++ b/doc/tut2.md
@@ -166,7 +166,7 @@ An example:
   n.strVal = ""
   ```
 
-As can been seen from the example, an advantage to an object hierarchy is that
+As can be seen from the example, an advantage to an object hierarchy is that
 no conversion between different object types is needed. Yet, access to invalid
 object fields raises an exception.
 
diff --git a/doc/tut3.md b/doc/tut3.md
index 67f49c879..3a55d4790 100644
--- a/doc/tut3.md
+++ b/doc/tut3.md
@@ -322,6 +322,36 @@ used to get this output.
     raise newException(AssertionDefect, $a & " != " & $b)
   ```
 
+
+Going further
+-------------
+
+It is possible to create more complex macros by combining different
+`NimNode` symbols with `quote do:` expressions. For example, you may
+use `newStmtList` to build your macro iteratively, and `ident` in cases
+in which you wish to create an identifier from a string, as shown below.
+
+  ```nim
+  import std/macros
+
+  macro createProcedures() =
+    result = newStmtList()
+
+    for i in 0..<10:
+      let name = ident("myProc" & $i)
+      let content = newLit("I am procedure number #" & $i)
+
+      result.add quote do:
+        proc `name`() =
+          echo `content`
+
+  createProcedures()
+  myProc7()
+  ```
+
+The call to `myProc7` will echo `I am procedure number #7`.
+
+
 With Power Comes Responsibility
 -------------------------------
 
diff --git a/koch.nim b/koch.nim
index f8e8980d2..77bc2299f 100644
--- a/koch.nim
+++ b/koch.nim
@@ -1,19 +1,19 @@
 #
 #
 #         Maintenance program for Nim
-#        (c) Copyright 2017 Andreas Rumpf
+#        (c) Copyright 2024 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
-#    See doc/koch.txt for documentation.
+#    See doc/koch.md for documentation.
 #
 
 const
   # examples of possible values for repos: Head, ea82b54
-  NimbleStableCommit = "39b61c5d85afffd53aa404ac9126419ae1bd8d67" # master
+  NimbleStableCommit = "4fb6f8e6c33963f6f510fe82d09ad2a61b5e4265" # 0.16.1
   AtlasStableCommit = "5faec3e9a33afe99a7d22377dd1b45a5391f5504"
-  ChecksumsStableCommit = "025bcca3915a1b9f19878cea12ad68f9884648fc"
+  ChecksumsStableCommit = "bd9bf4eaea124bf8d01e08f92ac1b14c6879d8d3"
   SatStableCommit = "faf1617f44d7632ee9601ebc13887644925dcc01"
 
   # examples of possible values for fusion: #head, #ea82b54, 1.2.3
@@ -52,7 +52,7 @@ const
 +-----------------------------------------------------------------+
 |         Maintenance program for Nim                             |
 |             Version $1|
-|             (c) 2017 Andreas Rumpf                              |
+|             (c) 2024 Andreas Rumpf                              |
 +-----------------------------------------------------------------+
 Build time: $2, $3
 
@@ -77,6 +77,7 @@ Possible Commands:
                            doesn't require network connectivity
   nimble                   builds the Nimble tool
   atlas                    builds the Atlas tool
+  checksums                installs the checksums dependency
   fusion                   installs fusion via Nimble
 
 Boot options:
@@ -160,6 +161,8 @@ proc bundleNimbleExe(latest: bool, args: string) =
                   commit = commit, allowBundled = true)
   cloneDependency(distDir / "nimble" / distDir, "https://github.com/nim-lang/checksums.git",
                 commit = ChecksumsStableCommit, allowBundled = true) # or copy it from dist?
+  cloneDependency(distDir / "nimble" / distDir, "https://github.com/nim-lang/sat.git",
+                commit = SatStableCommit, allowBundled = true)
   # installer.ini expects it under $nim/bin
   nimCompile("dist/nimble/src/nimble.nim",
              options = "-d:release -d:nimNimbleBootstrap --noNimblePath " & args)
@@ -342,8 +345,7 @@ proc boot(args: string, skipIntegrityCheck: bool) =
   let smartNimcache = (if "release" in args or "danger" in args: "nimcache/r_" else: "nimcache/d_") &
                       hostOS & "_" & hostCPU
 
-  if not dirExists("dist/checksums"):
-    bundleChecksums(false)
+  bundleChecksums(false)
 
   let usingLibFFI = "nimHasLibFFI" in args
   if usingLibFFI and not dirExists("dist/libffi"):
@@ -506,8 +508,7 @@ proc temp(args: string) =
       result[1].add " " & quoteShell(args[i])
       inc i
 
-  if not dirExists("dist/checksums"):
-    bundleChecksums(false)
+  bundleChecksums(false)
 
   let d = getAppDir()
   let output = d / "compiler" / "nim".exe
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index bd1de9cd7..7646b165c 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -93,6 +93,8 @@ type
     nnkFuncDef,
     nnkTupleConstr,
     nnkError,  ## erroneous AST node
+    nnkModuleRef, nnkReplayAction, nnkNilRodNode ## internal IC nodes
+    nnkOpenSym
 
   NimNodeKinds* = set[NimNodeKind]
   NimTypeKind* = enum  # some types are no longer used, see ast.nim
@@ -277,7 +279,7 @@ when (NimMajor, NimMinor, NimPatch) >= (1, 3, 5) or defined(nimSymImplTransform)
     ## note that code transformations are implementation dependent and subject to change.
     ## See an example in `tests/macros/tmacros_various.nim`.
 
-proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.}
+proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect, deprecated.}
   ## Accepts a node of kind `nnkSym` and returns its owner's symbol.
   ## The meaning of 'owner' depends on `sym`'s `NimSymKind` and declaration
   ## context. For top level declarations this is an `nskModule` symbol,
@@ -1407,7 +1409,7 @@ proc `$`*(node: NimNode): string =
     result = node.basename.strVal & "*"
   of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkSym, nnkIdent:
     result = node.strVal
-  of nnkOpenSymChoice, nnkClosedSymChoice:
+  of nnkOpenSymChoice, nnkClosedSymChoice, nnkOpenSym:
     result = $node[0]
   of nnkAccQuoted:
     result = ""
diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim
index 5075c8458..f2fee91c4 100644
--- a/lib/core/typeinfo.nim
+++ b/lib/core/typeinfo.nim
@@ -129,7 +129,9 @@ when not defined(gcDestructors):
 else:
   proc nimNewObj(size, align: int): pointer {.importCompilerProc.}
   proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.importCompilerProc.}
-  proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
+  proc prepareSeqAddUninit(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
+    importCompilerProc.}
+  proc zeroNewElements(len: int; p: pointer; addlen, elemSize, elemAlign: int) {.
     importCompilerProc.}
 
 template `+!!`(a, b): untyped = cast[pointer](cast[int](a) + b)
@@ -159,16 +161,6 @@ proc newAny(value: pointer, rawType: PNimType): Any {.inline.} =
   result.value = value
   result.rawType = rawType
 
-when declared(system.VarSlot):
-  proc toAny*(x: VarSlot): Any {.inline.} =
-    ## Constructs an `Any` object from a variable slot `x`.
-    ## This captures `x`'s address, so `x` can be modified with its
-    ## `Any` wrapper! The caller needs to ensure that the wrapper
-    ## **does not** live longer than `x`!
-    ## This is provided for easier reflection capabilities of a debugger.
-    result.value = x.address
-    result.rawType = x.typ
-
 proc toAny*[T](x: var T): Any {.inline.} =
   ## Constructs an `Any` object from `x`. This captures `x`'s address, so
   ## `x` can be modified with its `Any` wrapper! The caller needs to ensure
@@ -221,7 +213,8 @@ proc extendSeq*(x: Any) =
     var s = cast[ptr NimSeqV2Reimpl](x.value)
     let elem = x.rawType.base
     if s.p == nil or s.p.cap < s.len+1:
-      s.p = cast[ptr NimSeqPayloadReimpl](prepareSeqAdd(s.len, s.p, 1, elem.size, elem.align))
+      s.p = cast[ptr NimSeqPayloadReimpl](prepareSeqAddUninit(s.len, s.p, 1, elem.size, elem.align))
+    zeroNewElements(s.len, s.p, 1, elem.size, elem.align)
     inc s.len
   else:
     var y = cast[ptr PGenSeq](x.value)[]
diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim
index b7ebc905f..9b043f3e5 100644
--- a/lib/js/asyncjs.nim
+++ b/lib/js/asyncjs.nim
@@ -243,7 +243,7 @@ since (1, 5, 1):
     else:
       type A = impl(onSuccess(default(T)))
     var ret: A
-    {.emit: "`ret` = `future`.then(`onSuccess`, `onReject`)".}
+    {.emit: "`ret` = `future`.then(`onSuccess`, `onReject`);".}
     return ret
 
   proc catch*[T](future: Future[T], onReject: OnReject): Future[void] =
@@ -266,4 +266,4 @@ since (1, 5, 1):
 
       discard main()
 
-    {.emit: "`result` = `future`.catch(`onReject`)".}
+    {.emit: "`result` = `future`.catch(`onReject`);".}
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 2204987db..cf0c8002b 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -14,6 +14,7 @@ __GNUC__
 __TINYC__
 __clang__
 __AVR__
+__arm__
 __EMSCRIPTEN__
 */
 
@@ -272,11 +273,15 @@ __EMSCRIPTEN__
 #elif defined(__cplusplus)
 #define NIM_STATIC_ASSERT(x, msg) static_assert((x), msg)
 #else
-#define NIM_STATIC_ASSERT(x, msg) typedef int NIM_STATIC_ASSERT_AUX[(x) ? 1 : -1];
+#define _NIM_STATIC_ASSERT_FINAL(x, append_name) typedef int NIM_STATIC_ASSERT_AUX ## append_name[(x) ? 1 : -1];
+#define _NIM_STATIC_ASSERT_STAGE_3(x, line)      _NIM_STATIC_ASSERT_FINAL(x, _AT_LINE_##line)
+#define _NIM_STATIC_ASSERT_STAGE_2(x, line)      _NIM_STATIC_ASSERT_STAGE_3(x, line)
+#define NIM_STATIC_ASSERT(x, msg)                _NIM_STATIC_ASSERT_STAGE_2(x,__LINE__)
 // On failure, your C compiler will say something like:
-//   "error: 'NIM_STATIC_ASSERT_AUX' declared as an array with a negative size"
-// we could use a better fallback to also show line number, using:
-// http://www.pixelbeat.org/programming/gcc/static_assert.html
+//   "error: 'NIM_STATIC_ASSERT_AUX_AT_LINE_XXX' declared as an array with a negative size"
+// Adding the line number helps to avoid redefinitions which are not allowed in
+// old GCC versions, however the order of evaluation for __LINE__ is a little tricky,
+// hence all the helper macros. See https://stackoverflow.com/a/3385694 for more info.
 #endif
 
 /* C99 compiler? */
@@ -473,7 +478,7 @@ typedef char* NCSTRING;
 /* declared size of a sequence/variable length array: */
 #if defined(__cplusplus) && defined(__clang__)
 #  define SEQ_DECL_SIZE 1
-#elif defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
+#elif defined(__GNUC__) || defined(_MSC_VER)
 #  define SEQ_DECL_SIZE /* empty is correct! */
 #else
 #  define SEQ_DECL_SIZE 1000000
@@ -580,9 +585,16 @@ NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, "P
   #define nimMulInt64(a, b, res) __builtin_smulll_overflow(a, b, (long long int*)res)
 
   #if NIM_INTBITS == 32
-    #define nimAddInt(a, b, res) __builtin_sadd_overflow(a, b, res)
-    #define nimSubInt(a, b, res) __builtin_ssub_overflow(a, b, res)
-    #define nimMulInt(a, b, res) __builtin_smul_overflow(a, b, res)
+    #if defined(__arm__) && defined(__GNUC__)
+      /* arm-none-eabi-gcc targets defines int32_t as long int */
+      #define nimAddInt(a, b, res) __builtin_saddl_overflow(a, b, res)
+      #define nimSubInt(a, b, res) __builtin_ssubl_overflow(a, b, res)
+      #define nimMulInt(a, b, res) __builtin_smull_overflow(a, b, res)
+    #else
+      #define nimAddInt(a, b, res) __builtin_sadd_overflow(a, b, res)
+      #define nimSubInt(a, b, res) __builtin_ssub_overflow(a, b, res)
+      #define nimMulInt(a, b, res) __builtin_smul_overflow(a, b, res)
+    #endif
   #else
     /* map it to the 'long long' variant */
     #define nimAddInt(a, b, res) __builtin_saddll_overflow(a, b, (long long int*)res)
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 9af163e15..706c50689 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -1526,7 +1526,7 @@ proc parseMarkdownCodeblockFields(p: var RstParser): PRstNode =
     result = nil
   else:
     result = newRstNode(rnFieldList)
-  while currentTok(p).kind != tkIndent:
+  while currentTok(p).kind notin {tkIndent, tkEof}:
     if currentTok(p).kind == tkWhite:
       inc p.idx
     else:
@@ -1603,6 +1603,7 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode =
   else:
     args = nil
   var n = newLeaf("")
+  var isFirstLine = true
   while true:
     if currentTok(p).kind == tkEof:
       rstMessage(p, meMissingClosing,
@@ -1614,7 +1615,8 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode =
       inc p.idx, 2
       break
     elif currentTok(p).kind == tkIndent:
-      n.text.add "\n"
+      if not isFirstLine:
+        n.text.add "\n"
       if currentTok(p).ival > baseCol:
         n.text.add " ".repeat(currentTok(p).ival - baseCol)
       elif currentTok(p).ival < baseCol:
@@ -1624,6 +1626,7 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode =
     else:
       n.text.add(currentTok(p).symbol)
       inc p.idx
+    isFirstLine = false
   result.sons[0] = args
   if result.sons[2] == nil:
     var lb = newRstNode(rnLiteralBlock)
diff --git a/lib/posix/inotify.nim b/lib/posix/inotify.nim
index 7bc1504e5..575accc18 100644
--- a/lib/posix/inotify.nim
+++ b/lib/posix/inotify.nim
@@ -20,7 +20,7 @@ type
     mask* {.importc: "mask".}: uint32                  ## Watch mask.
     cookie* {.importc: "cookie".}: uint32              ## Cookie to synchronize two events.
     len* {.importc: "len".}: uint32                    ## Length (including NULs) of name.
-    name* {.importc: "name".}: char                    ## Name.
+    name* {.importc: "name".}: UncheckedArray[char]    ## Name.
 
 # Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH.
 const
@@ -67,7 +67,8 @@ proc inotify_init*(): FileHandle {.cdecl, importc: "inotify_init",
 
 proc inotify_init1*(flags: cint): FileHandle {.cdecl, importc: "inotify_init1",
     header: "<sys/inotify.h>".}
-  ## Create and initialize inotify instance.
+  ## Like `inotify_init<#inotify_init>`_ ,
+  ## but has a flags argument that provides access to some extra functionality.
 
 proc inotify_add_watch*(fd: cint; name: cstring; mask: uint32): cint {.cdecl,
     importc: "inotify_add_watch", header: "<sys/inotify.h>".}
@@ -79,11 +80,18 @@ proc inotify_rm_watch*(fd: cint; wd: cint): cint {.cdecl,
 
 iterator inotify_events*(evs: pointer, n: int): ptr InotifyEvent =
   ## Abstract the packed buffer interface to yield event object pointers.
-  ##   ```Nim
-  ##   var evs = newSeq[byte](8192)        # Already did inotify_init+add_watch
-  ##   while (let n = read(fd, evs[0].addr, 8192); n) > 0:     # read forever
-  ##     for e in inotify_events(evs[0].addr, n): echo e[].len # echo name lens
-  ##   ```
+  runnableExamples("-r:off"):
+    when defined(linux):
+       import std/posix  # needed for FileHandle read procedure
+       const MaxWatches = 8192
+
+       let inotifyFd = inotify_init()  # create new inotify instance and get it's FileHandle
+       let wd = inotifyFd.inotify_add_watch("/tmp", IN_CREATE or IN_DELETE)  # Add new watch
+
+       var events: array[MaxWatches, byte]  # event buffer
+       while (let n = read(inotifyFd, addr events, MaxWatches); n) > 0:  # blocks until any events have been read
+         for e in inotify_events(addr events, n):
+           echo (e[].wd, e[].mask, cast[cstring](addr e[].name))    # echo watch id, mask, and name value of each event
   var ev: ptr InotifyEvent = cast[ptr InotifyEvent](evs)
   var n = n
   while n > 0:
@@ -94,8 +102,10 @@ iterator inotify_events*(evs: pointer, n: int): ptr InotifyEvent =
 
 runnableExamples:
   when defined(linux):
-    let inoty: FileHandle = inotify_init()           ## Create 1 Inotify.
-    doAssert inoty >= 0                              ## Check for errors (FileHandle is alias to cint).
-    let watchdoge: cint = inotify_add_watch(inoty, ".", IN_ALL_EVENTS) ## Add directory to watchdog.
-    doAssert watchdoge >= 0                          ## Check for errors.
-    doAssert inotify_rm_watch(inoty, watchdoge) >= 0 ## Remove directory from the watchdog
+    let inotifyFd = inotify_init()  # create and get new inotify FileHandle
+    doAssert inotifyFd >= 0         # check for errors
+
+    let wd = inotifyFd.inotify_add_watch("/tmp", IN_CREATE or IN_DELETE)  # Add new watch
+    doAssert wd >= 0                 # check for errors
+
+    discard inotifyFd.inotify_rm_watch(wd) # remove watch
diff --git a/lib/posix/posix_macos_amd64.nim b/lib/posix/posix_macos_amd64.nim
index d6b5834cb..a4b64ed62 100644
--- a/lib/posix/posix_macos_amd64.nim
+++ b/lib/posix/posix_macos_amd64.nim
@@ -122,10 +122,14 @@ type
     ## used for block sizes
   Clock* {.importc: "clock_t", header: "<sys/types.h>".} = int
   ClockId* {.importc: "clockid_t", header: "<sys/types.h>".} = int
-  Dev* {.importc: "dev_t", header: "<sys/types.h>".} = int32
+  Dev* {.importc: "dev_t", header: "<sys/types.h>".} = (
+    when defined(freebsd):
+      uint32
+    else:
+      int32)
   Fsblkcnt* {.importc: "fsblkcnt_t", header: "<sys/types.h>".} = int
   Fsfilcnt* {.importc: "fsfilcnt_t", header: "<sys/types.h>".} = int
-  Gid* {.importc: "gid_t", header: "<sys/types.h>".} = int32
+  Gid* {.importc: "gid_t", header: "<sys/types.h>".} = uint32
   Id* {.importc: "id_t", header: "<sys/types.h>".} = int
   Ino* {.importc: "ino_t", header: "<sys/types.h>".} = int
   Key* {.importc: "key_t", header: "<sys/types.h>".} = int
@@ -135,7 +139,7 @@ type
     else:
       uint16
   )
-  Nlink* {.importc: "nlink_t", header: "<sys/types.h>".} = int16
+  Nlink* {.importc: "nlink_t", header: "<sys/types.h>".} = uint16
   Off* {.importc: "off_t", header: "<sys/types.h>".} = int64
   Pid* {.importc: "pid_t", header: "<sys/types.h>".} = int32
   Pthread_attr* {.importc: "pthread_attr_t", header: "<sys/types.h>".} = int
@@ -167,7 +171,7 @@ type
   Trace_event_set* {.importc: "trace_event_set_t",
                       header: "<sys/types.h>".} = int
   Trace_id* {.importc: "trace_id_t", header: "<sys/types.h>".} = int
-  Uid* {.importc: "uid_t", header: "<sys/types.h>".} = int32
+  Uid* {.importc: "uid_t", header: "<sys/types.h>".} = uint32
   Useconds* {.importc: "useconds_t", header: "<sys/types.h>".} = int
 
   Utsname* {.importc: "struct utsname",
@@ -462,9 +466,9 @@ type
                    header: "<netinet/in.h>".} = object ## struct sockaddr_in6
     sin6_family*: TSa_Family ## AF_INET6.
     sin6_port*: InPort      ## Port number.
-    sin6_flowinfo*: int32    ## IPv6 traffic class and flow information.
+    sin6_flowinfo*: uint32    ## IPv6 traffic class and flow information.
     sin6_addr*: In6Addr     ## IPv6 address.
-    sin6_scope_id*: int32    ## Set of interfaces for a scope.
+    sin6_scope_id*: uint32    ## Set of interfaces for a scope.
 
   Tipv6_mreq* {.importc: "struct ipv6_mreq", pure, final,
                 header: "<netinet/in.h>".} = object ## struct ipv6_mreq
@@ -491,7 +495,7 @@ type
                              ## alternative network names, terminated by a
                              ## null pointer.
     n_addrtype*: cint        ## The address type of the network.
-    n_net*: int32            ## The network number, in host byte order.
+    n_net*: uint32            ## The network number, in host byte order.
 
   Protoent* {.importc: "struct protoent", pure, final,
               header: "<netdb.h>".} = object ## struct protoent
diff --git a/lib/posix/posix_openbsd_amd64.nim b/lib/posix/posix_openbsd_amd64.nim
index 1ef4a4182..184cd89c0 100644
--- a/lib/posix/posix_openbsd_amd64.nim
+++ b/lib/posix/posix_openbsd_amd64.nim
@@ -131,15 +131,19 @@ type
     ## used for block sizes
   Clock* {.importc: "clock_t", header: "<sys/types.h>".} = int
   ClockId* {.importc: "clockid_t", header: "<sys/types.h>".} = int
-  Dev* {.importc: "dev_t", header: "<sys/types.h>".} = int32
+  Dev* {.importc: "dev_t", header: "<sys/types.h>".} = (
+    when defined(freebsd):
+      uint32
+    else:
+      int32)
   Fsblkcnt* {.importc: "fsblkcnt_t", header: "<sys/types.h>".} = int
   Fsfilcnt* {.importc: "fsfilcnt_t", header: "<sys/types.h>".} = int
-  Gid* {.importc: "gid_t", header: "<sys/types.h>".} = int32
+  Gid* {.importc: "gid_t", header: "<sys/types.h>".} = uint32
   Id* {.importc: "id_t", header: "<sys/types.h>".} = int
   Ino* {.importc: "ino_t", header: "<sys/types.h>".} = int
   Key* {.importc: "key_t", header: "<sys/types.h>".} = int
   Mode* {.importc: "mode_t", header: "<sys/types.h>".} = uint32
-  Nlink* {.importc: "nlink_t", header: "<sys/types.h>".} = int16
+  Nlink* {.importc: "nlink_t", header: "<sys/types.h>".} = uint32
   Off* {.importc: "off_t", header: "<sys/types.h>".} = int64
   Pid* {.importc: "pid_t", header: "<sys/types.h>".} = int32
   Pthread_attr* {.importc: "pthread_attr_t", header: "<pthread.h>".} = int
@@ -171,7 +175,7 @@ type
   Trace_event_set* {.importc: "trace_event_set_t",
                       header: "<sys/types.h>".} = int
   Trace_id* {.importc: "trace_id_t", header: "<sys/types.h>".} = int
-  Uid* {.importc: "uid_t", header: "<sys/types.h>".} = int32
+  Uid* {.importc: "uid_t", header: "<sys/types.h>".} = uint32
   Useconds* {.importc: "useconds_t", header: "<sys/types.h>".} = int
 
   Utsname* {.importc: "struct utsname",
@@ -446,9 +450,9 @@ type
                    header: "<netinet/in.h>".} = object ## struct sockaddr_in6
     sin6_family*: TSa_Family ## AF_INET6.
     sin6_port*: InPort      ## Port number.
-    sin6_flowinfo*: int32    ## IPv6 traffic class and flow information.
+    sin6_flowinfo*: uint32    ## IPv6 traffic class and flow information.
     sin6_addr*: In6Addr     ## IPv6 address.
-    sin6_scope_id*: int32    ## Set of interfaces for a scope.
+    sin6_scope_id*: uint32    ## Set of interfaces for a scope.
 
   Tipv6_mreq* {.importc: "struct ipv6_mreq", pure, final,
                 header: "<netinet/in.h>".} = object ## struct ipv6_mreq
@@ -475,7 +479,7 @@ type
                              ## alternative network names, terminated by a
                              ## null pointer.
     n_addrtype*: cint        ## The address type of the network.
-    n_net*: int32            ## The network number, in host byte order.
+    n_net*: uint32            ## The network number, in host byte order.
 
   Protoent* {.importc: "struct protoent", pure, final,
               header: "<netdb.h>".} = object ## struct protoent
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index d8dc7a798..ee07e599e 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -687,7 +687,7 @@ when defined(posix) and not useNimNetLite:
 
       var socketAddr = makeUnixAddr(path)
       let ret = socket.fd.connect(cast[ptr SockAddr](addr socketAddr),
-                        (sizeof(socketAddr.sun_family) + path.len).SockLen)
+                        (offsetOf(socketAddr, sun_path) + path.len + 1).SockLen)
       if ret == 0:
         # Request to connect completed immediately.
         retFuture.complete()
@@ -705,7 +705,7 @@ when defined(posix) and not useNimNetLite:
     when not defined(nimdoc):
       var socketAddr = makeUnixAddr(path)
       if socket.fd.bindAddr(cast[ptr SockAddr](addr socketAddr),
-          (sizeof(socketAddr.sun_family) + path.len).SockLen) != 0'i32:
+          (offsetOf(socketAddr, sun_path) + path.len + 1).SockLen) != 0'i32:
         raiseOSError(osLastError())
 
 elif defined(nimdoc):
diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim
index 8234db410..b48811eae 100644
--- a/lib/pure/complex.nim
+++ b/lib/pure/complex.nim
@@ -15,9 +15,6 @@
 runnableExamples:
   from std/math import almostEqual, sqrt
 
-  func almostEqual(a, b: Complex): bool =
-    almostEqual(a.re, b.re) and almostEqual(a.im, b.im)
-
   let
     z1 = complex(1.0, 2.0)
     z2 = complex(3.0, -4.0)
@@ -412,6 +409,24 @@ func rect*[T](r, phi: T): Complex[T] =
   ## * `polar func<#polar,Complex[T]>`_ for the inverse operation
   complex(r * cos(phi), r * sin(phi))
 
+func almostEqual*[T: SomeFloat](x, y: Complex[T]; unitsInLastPlace: Natural = 4): bool =
+  ## Checks if two complex values are almost equal, using the
+  ## [machine epsilon](https://en.wikipedia.org/wiki/Machine_epsilon).
+  ##
+  ## Two complex values are considered almost equal if their real and imaginary
+  ## components are almost equal.
+  ##
+  ## `unitsInLastPlace` is the max number of
+  ## [units in the last place](https://en.wikipedia.org/wiki/Unit_in_the_last_place)
+  ## difference tolerated when comparing two numbers. The larger the value, the
+  ## more error is allowed. A `0` value means that two numbers must be exactly the
+  ## same to be considered equal.
+  ##
+  ## The machine epsilon has to be scaled to the magnitude of the values used
+  ## and multiplied by the desired precision in ULPs unless the difference is
+  ## subnormal.
+  almostEqual(x.re, y.re, unitsInLastPlace = unitsInLastPlace) and
+  almostEqual(x.im, y.im, unitsInLastPlace = unitsInLastPlace)
 
 func `$`*(z: Complex): string =
   ## Returns `z`'s string representation as `"(re, im)"`.
diff --git a/lib/pure/concurrency/atomics.nim b/lib/pure/concurrency/atomics.nim
index c7b881bc5..818f1b37a 100644
--- a/lib/pure/concurrency/atomics.nim
+++ b/lib/pure/concurrency/atomics.nim
@@ -10,6 +10,9 @@
 ## Types and operations for atomic operations and lockless algorithms.
 ##
 ## Unstable API.
+## 
+## By default, C++ uses C11 atomic primitives. To use C++ `std::atomic`,
+## `-d:nimUseCppAtomics` can be defined.
 
 runnableExamples:
   # Atomic
@@ -50,8 +53,7 @@ runnableExamples:
   flag.clear(moRelaxed)
   assert not flag.testAndSet
 
-
-when defined(cpp) or defined(nimdoc):
+when (defined(cpp) and defined(nimUseCppAtomics)) or defined(nimdoc):
   # For the C++ backend, types and operations map directly to C++11 atomics.
 
   {.push, header: "<atomic>".}
@@ -274,10 +276,17 @@ else:
       cast[T](interlockedXor(addr(location.value), cast[nonAtomicType(T)](value)))
 
   else:
-    {.push, header: "<stdatomic.h>".}
+    when defined(cpp):
+      {.push, header: "<atomic>".}
+      template maybeWrapStd(x: string): string =
+        "std::" & x
+    else:
+      {.push, header: "<stdatomic.h>".}
+      template maybeWrapStd(x: string): string =
+        x
 
     type
-      MemoryOrder* {.importc: "memory_order".} = enum
+      MemoryOrder* {.importc: "memory_order".maybeWrapStd.} = enum
         moRelaxed
         moConsume
         moAcquire
@@ -285,16 +294,25 @@ else:
         moAcquireRelease
         moSequentiallyConsistent
 
-    type
-      # Atomic*[T] {.importcpp: "_Atomic('0)".} = object
+    when defined(cpp):
+      type
+        # Atomic*[T] {.importcpp: "_Atomic('0)".} = object
+
+        AtomicInt8 {.importc: "std::atomic<NI8>".} = int8
+        AtomicInt16 {.importc: "std::atomic<NI16>".} = int16
+        AtomicInt32 {.importc: "std::atomic<NI32>".} = int32
+        AtomicInt64 {.importc: "std::atomic<NI64>".} = int64
+    else:
+      type
+        # Atomic*[T] {.importcpp: "_Atomic('0)".} = object
 
-      AtomicInt8 {.importc: "_Atomic NI8".} = int8
-      AtomicInt16 {.importc: "_Atomic NI16".} = int16
-      AtomicInt32 {.importc: "_Atomic NI32".} = int32
-      AtomicInt64 {.importc: "_Atomic NI64".} = int64
+        AtomicInt8 {.importc: "_Atomic NI8".} = int8
+        AtomicInt16 {.importc: "_Atomic NI16".} = int16
+        AtomicInt32 {.importc: "_Atomic NI32".} = int32
+        AtomicInt64 {.importc: "_Atomic NI64".} = int64
 
     type
-      AtomicFlag* {.importc: "atomic_flag", size: 1.} = object
+      AtomicFlag* {.importc: "atomic_flag".maybeWrapStd, size: 1.} = object
 
       Atomic*[T] = object
         when T is Trivial:
@@ -308,27 +326,27 @@ else:
           guard: AtomicFlag
 
     #proc init*[T](location: var Atomic[T]; value: T): T {.importcpp: "atomic_init(@)".}
-    proc atomic_load_explicit[T, A](location: ptr A; order: MemoryOrder): T {.importc.}
-    proc atomic_store_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.importc.}
-    proc atomic_exchange_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
-    proc atomic_compare_exchange_strong_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc.}
-    proc atomic_compare_exchange_weak_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc.}
+    proc atomic_load_explicit[T, A](location: ptr A; order: MemoryOrder): T {.importc: "atomic_load_explicit".maybeWrapStd.}
+    proc atomic_store_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.importc: "atomic_store_explicit".maybeWrapStd.}
+    proc atomic_exchange_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_exchange_explicit".maybeWrapStd.}
+    proc atomic_compare_exchange_strong_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc: "atomic_compare_exchange_strong_explicit".maybeWrapStd.}
+    proc atomic_compare_exchange_weak_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc: "atomic_compare_exchange_weak_explicit".maybeWrapStd.}
 
     # Numerical operations
-    proc atomic_fetch_add_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
-    proc atomic_fetch_sub_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
-    proc atomic_fetch_and_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
-    proc atomic_fetch_or_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
-    proc atomic_fetch_xor_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
+    proc atomic_fetch_add_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_add_explicit".maybeWrapStd.}
+    proc atomic_fetch_sub_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_sub_explicit".maybeWrapStd.}
+    proc atomic_fetch_and_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_and_explicit".maybeWrapStd.}
+    proc atomic_fetch_or_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_or_explicit".maybeWrapStd.}
+    proc atomic_fetch_xor_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_xor_explicit".maybeWrapStd.}
 
     # Flag operations
     # var ATOMIC_FLAG_INIT {.importc, nodecl.}: AtomicFlag
     # proc init*(location: var AtomicFlag) {.inline.} = location = ATOMIC_FLAG_INIT
-    proc testAndSet*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent): bool {.importc: "atomic_flag_test_and_set_explicit".}
-    proc clear*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent) {.importc: "atomic_flag_clear_explicit".}
+    proc testAndSet*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent): bool {.importc: "atomic_flag_test_and_set_explicit".maybeWrapStd.}
+    proc clear*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent) {.importc: "atomic_flag_clear_explicit".maybeWrapStd.}
 
-    proc fence*(order: MemoryOrder) {.importc: "atomic_thread_fence".}
-    proc signalFence*(order: MemoryOrder) {.importc: "atomic_signal_fence".}
+    proc fence*(order: MemoryOrder) {.importc: "atomic_thread_fence".maybeWrapStd.}
+    proc signalFence*(order: MemoryOrder) {.importc: "atomic_signal_fence".maybeWrapStd.}
 
     {.pop.}
 
diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim
index 0b2c915b2..9bc3fd579 100644
--- a/lib/pure/concurrency/cpuinfo.nim
+++ b/lib/pure/concurrency/cpuinfo.nim
@@ -15,75 +15,96 @@ runnableExamples:
 
 include "system/inclrtl"
 
-when defined(posix) and not (defined(macosx) or defined(bsd)):
-  import std/posix
+when defined(js):
+  import std/jsffi
+  proc countProcessorsImpl(): int =
+    when defined(nodejs):
+      let jsOs = require("os")
+      let jsObj = jsOs.cpus().length
+    else:
+      # `navigator.hardwareConcurrency`
+      # works on browser as well as deno.
+      let navigator{.importcpp.}: JsObject
+      let jsObj = navigator.hardwareConcurrency
+    result = jsObj.to int
+else:
+  when defined(posix) and not (defined(macosx) or defined(bsd)):
+    import std/posix
 
-when defined(windows):
-  import std/private/win_getsysteminfo
+  when defined(windows):
+    import std/private/win_getsysteminfo
+
+  when defined(freebsd) or defined(macosx):
+    {.emit: "#include <sys/types.h>".}
+
+  when defined(openbsd) or defined(netbsd):
+    {.emit: "#include <sys/param.h>".}
 
-when defined(freebsd) or defined(macosx):
-  {.emit: "#include <sys/types.h>".}
+  when defined(macosx) or defined(bsd):
+    # we HAVE to emit param.h before sysctl.h so we cannot use .header here
+    # either. The amount of archaic bullshit in Poonix based OSes is just insane.
+    {.emit: "#include <sys/sysctl.h>".}
+    {.push nodecl.}
+    when defined(macosx):
+      proc sysctlbyname(name: cstring,
+        oldp: pointer, oldlenp: var csize_t,
+        newp: pointer, newlen: csize_t): cint {.importc.}
+    let
+      CTL_HW{.importc.}: cint
+      HW_NCPU{.importc.}: cint
+    proc sysctl[I: static[int]](name: var array[I, cint], namelen: cuint,
+      oldp: pointer, oldlenp: var csize_t,
+      newp: pointer, newlen: csize_t): cint {.importc.}
+    {.pop.}
 
-when defined(openbsd) or defined(netbsd):
-  {.emit: "#include <sys/param.h>".}
+  when defined(genode):
+    import genode/env
 
-when defined(macosx) or defined(bsd):
-  # we HAVE to emit param.h before sysctl.h so we cannot use .header here
-  # either. The amount of archaic bullshit in Poonix based OSes is just insane.
-  {.emit: "#include <sys/sysctl.h>".}
-  const
-    CTL_HW = 6
-    HW_AVAILCPU = 25
-    HW_NCPU = 3
-  proc sysctl(x: ptr array[0..3, cint], y: cint, z: pointer,
-              a: var csize_t, b: pointer, c: csize_t): cint {.
-              importc: "sysctl", nodecl.}
+    proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
+      importcpp: "@->cpu().affinity_space().total()".}
 
-when defined(genode):
-  import genode/env
+  when defined(haiku):
+    type
+      SystemInfo {.importc: "system_info", header: "<OS.h>".} = object
+        cpuCount {.importc: "cpu_count".}: uint32
 
-  proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
-    importcpp: "@->cpu().affinity_space().total()".}
+    proc getSystemInfo(info: ptr SystemInfo): int32 {.importc: "get_system_info",
+                                                      header: "<OS.h>".}
+
+  proc countProcessorsImpl(): int {.inline.} =
+    when defined(windows):
+      var
+        si: SystemInfo
+      getSystemInfo(addr si)
+      result = int(si.dwNumberOfProcessors)
+    elif defined(macosx) or defined(bsd):
+      let dest = addr result
+      var len = sizeof(result).csize_t
+      when defined(macosx):
+        # alias of "hw.activecpu"
+        if sysctlbyname("hw.logicalcpu", dest, len, nil, 0) == 0:
+          return
+      var mib = [CTL_HW, HW_NCPU]
+      if sysctl(mib, 2, dest, len, nil, 0) == 0:
+        return
+    elif defined(hpux):
+      result = mpctl(MPC_GETNUMSPUS, nil, nil)
+    elif defined(irix):
+      var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint
+      result = sysconf(SC_NPROC_ONLN)
+    elif defined(genode):
+      result = runtimeEnv.affinitySpaceTotal().int
+    elif defined(haiku):
+      var sysinfo: SystemInfo
+      if getSystemInfo(addr sysinfo) == 0:
+        result = sysinfo.cpuCount.int
+    else:
+      result = sysconf(SC_NPROCESSORS_ONLN)
+    if result < 0: result = 0
 
-when defined(haiku):
-  type
-    SystemInfo {.importc: "system_info", header: "<OS.h>".} = object
-      cpuCount {.importc: "cpu_count".}: uint32
 
-  proc getSystemInfo(info: ptr SystemInfo): int32 {.importc: "get_system_info",
-                                                    header: "<OS.h>".}
 
 proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
   ## Returns the number of the processors/cores the machine has.
   ## Returns 0 if it cannot be detected.
-  when defined(windows):
-    var
-      si: SystemInfo
-    getSystemInfo(addr si)
-    result = int(si.dwNumberOfProcessors)
-  elif defined(macosx) or defined(bsd):
-    var
-      mib: array[0..3, cint]
-      numCPU: int
-    mib[0] = CTL_HW
-    mib[1] = HW_AVAILCPU
-    var len = sizeof(numCPU).csize_t
-    discard sysctl(addr(mib), 2, addr(numCPU), len, nil, 0)
-    if numCPU < 1:
-      mib[1] = HW_NCPU
-      discard sysctl(addr(mib), 2, addr(numCPU), len, nil, 0)
-    result = numCPU
-  elif defined(hpux):
-    result = mpctl(MPC_GETNUMSPUS, nil, nil)
-  elif defined(irix):
-    var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint
-    result = sysconf(SC_NPROC_ONLN)
-  elif defined(genode):
-    result = runtimeEnv.affinitySpaceTotal().int
-  elif defined(haiku):
-    var sysinfo: SystemInfo
-    if getSystemInfo(addr sysinfo) == 0:
-      result = sysinfo.cpuCount.int
-  else:
-    result = sysconf(SC_NPROCESSORS_ONLN)
-  if result <= 0: result = 0
+  countProcessorsImpl()
diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim
index 58eacf633..9e71d4ce0 100644
--- a/lib/pure/distros.nim
+++ b/lib/pure/distros.nim
@@ -127,6 +127,7 @@ type
 
     BSD
     FreeBSD
+    NetBSD
     OpenBSD
     DragonFlyBSD
 
@@ -168,7 +169,7 @@ proc detectOsImpl(d: Distribution): bool =
   else:
     when defined(bsd):
       case d
-      of Distribution.FreeBSD, Distribution.OpenBSD:
+      of Distribution.FreeBSD, Distribution.NetBSD, Distribution.OpenBSD:
         result = $d in uname()
       else:
         result = false
@@ -251,7 +252,7 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) =
       result = ("nix-env -i " & p, false)
     elif detectOs(Solaris) or detectOs(FreeBSD):
       result = ("pkg install " & p, true)
-    elif detectOs(OpenBSD):
+    elif detectOs(NetBSD) or detectOs(OpenBSD):
       result = ("pkg_add " & p, true)
     elif detectOs(PCLinuxOS):
       result = ("rpm -ivh " & p, true)
diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim
index ddb6a1a0c..1d96fd6be 100644
--- a/lib/pure/fenv.nim
+++ b/lib/pure/fenv.nim
@@ -12,7 +12,7 @@
 ## The types, vars and procs are bindings for the C standard library
 ## [<fenv.h>](https://en.cppreference.com/w/c/numeric/fenv) header.
 
-when defined(posix) and not defined(genode):
+when defined(posix) and not defined(genode) and not defined(macosx):
   {.passl: "-lm".}
 
 var
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index 518299511..1038d55a1 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -190,7 +190,7 @@ proc hashData*(data: pointer, size: int): Hash =
   var h: Hash = 0
   when defined(js):
     var p: cstring
-    {.emit: """`p` = `Data`""".}
+    {.emit: """`p` = `Data`;""".}
   else:
     var p = cast[cstring](data)
   var i = 0
@@ -379,6 +379,158 @@ proc hashVmImplChar(x: openArray[char], sPos, ePos: int): Hash =
 proc hashVmImplByte(x: openArray[byte], sPos, ePos: int): Hash =
   raiseAssert "implementation override in compiler/vmops.nim"
 
+const k0 = 0xc3a5c85c97cb3127u64 # Primes on (2^63, 2^64) for various uses
+const k1 = 0xb492b66fbe98f273u64
+const k2 = 0x9ae16a3b2f90404fu64
+
+proc load4e(s: openArray[byte], o=0): uint32 {.inline.} =
+  uint32(s[o + 3]) shl 24 or uint32(s[o + 2]) shl 16 or
+  uint32(s[o + 1]) shl  8 or uint32(s[o + 0])
+
+proc load8e(s: openArray[byte], o=0): uint64 {.inline.} =
+  uint64(s[o + 7]) shl 56 or uint64(s[o + 6]) shl 48 or
+  uint64(s[o + 5]) shl 40 or uint64(s[o + 4]) shl 32 or
+  uint64(s[o + 3]) shl 24 or uint64(s[o + 2]) shl 16 or
+  uint64(s[o + 1]) shl  8 or uint64(s[o + 0])
+
+proc load4(s: openArray[byte], o=0): uint32 {.inline.} =
+  when nimvm: result = load4e(s, o)
+  else:
+    when declared copyMem: copyMem result.addr, s[o].addr, result.sizeof
+    else: result = load4e(s, o)
+
+proc load8(s: openArray[byte], o=0): uint64 {.inline.} =
+  when nimvm: result = load8e(s, o)
+  else:
+    when declared copyMem: copyMem result.addr, s[o].addr, result.sizeof
+    else: result = load8e(s, o)
+
+proc lenU(s: openArray[byte]): uint64 {.inline.} = s.len.uint64
+
+proc shiftMix(v: uint64): uint64 {.inline.} = v xor (v shr 47)
+
+proc rotR(v: uint64; bits: cint): uint64 {.inline.} =
+  (v shr bits) or (v shl (64 - bits))
+
+proc len16(u: uint64; v: uint64; mul: uint64): uint64 {.inline.} =
+  var a = (u xor v)*mul
+  a = a xor (a shr 47)
+  var b = (v xor a)*mul
+  b = b xor (b shr 47)
+  b*mul
+
+proc len0_16(s: openArray[byte]): uint64 {.inline.} =
+  if s.len >= 8:
+    let mul = k2 + 2*s.lenU
+    let a   = load8(s) + k2
+    let b   = load8(s, s.len - 8)
+    let c   = rotR(b, 37)*mul + a
+    let d   = (rotR(a, 25) + b)*mul
+    len16 c, d, mul
+  elif s.len >= 4:
+    let mul = k2 + 2*s.lenU
+    let a   = load4(s).uint64
+    len16 s.lenU + (a shl 3), load4(s, s.len - 4), mul
+  elif s.len > 0:
+    let a = uint32(s[0])
+    let b = uint32(s[s.len shr 1])
+    let c = uint32(s[s.len - 1])
+    let y = a      + (b shl 8)
+    let z = s.lenU + (c shl 2)
+    shiftMix(y*k2 xor z*k0)*k2
+  else: k2      # s.len == 0
+
+proc len17_32(s: openArray[byte]): uint64 {.inline.} =
+  let mul = k2 + 2*s.lenU
+  let a = load8(s)*k1
+  let b = load8(s, 8)
+  let c = load8(s, s.len - 8)*mul
+  let d = load8(s, s.len - 16)*k2
+  len16 rotR(a + b, 43) + rotR(c, 30) + d, a + rotR(b + k2, 18) + c, mul
+
+proc len33_64(s: openArray[byte]): uint64 {.inline.} =
+  let mul = k2 + 2*s.lenU
+  let a = load8(s)*k2
+  let b = load8(s, 8)
+  let c = load8(s, s.len - 8)*mul
+  let d = load8(s, s.len - 16)*k2
+  let y = rotR(a + b, 43) + rotR(c, 30) + d
+  let z = len16(y, a + rotR(b + k2, 18) + c, mul)
+  let e = load8(s, 16)*mul
+  let f = load8(s, 24)
+  let g = (y + load8(s, s.len - 32))*mul
+  let h = (z + load8(s, s.len - 24))*mul
+  len16 rotR(e + f, 43) + rotR(g, 30) + h, e + rotR(f + a, 18) + g, mul
+
+type Pair = tuple[first, second: uint64]
+
+proc weakLen32withSeeds2(w, x, y, z, a, b: uint64): Pair {.inline.} =
+  var a = a + w
+  var b = rotR(b + a + z, 21)
+  let c = a
+  a += x
+  a += y
+  b += rotR(a, 44)
+  result[0] = a + z
+  result[1] = b + c
+
+proc weakLen32withSeeds(s: openArray[byte]; o: int; a,b: uint64): Pair {.inline.} =
+  weakLen32withSeeds2 load8(s, o     ), load8(s, o + 8),
+                      load8(s, o + 16), load8(s, o + 24), a, b
+
+proc hashFarm(s: openArray[byte]): uint64 {.inline.} =
+  if s.len <= 16: return len0_16(s)
+  if s.len <= 32: return len17_32(s)
+  if s.len <= 64: return len33_64(s)
+  const seed = 81u64 # not const to use input `h`
+  var
+    o = 0         # s[] ptr arith -> variable origin variable `o`
+    x = seed
+    y = seed*k1 + 113
+    z = shiftMix(y*k2 + 113)*k2
+    v, w: Pair
+  x = x*k2 + load8(s)
+  let eos    = ((s.len - 1) div 64)*64
+  let last64 = eos + ((s.len - 1) and 63) - 63
+  while true:
+    x = rotR(x + y + v[0] + load8(s, o+8), 37)*k1
+    y = rotR(y + v[1] + load8(s, o+48), 42)*k1
+    x = x xor w[1]
+    y += v[0] + load8(s, o+40)
+    z = rotR(z + w[0], 33)*k1
+    v = weakLen32withSeeds(s, o+0 , v[1]*k1, x + w[0])
+    w = weakLen32withSeeds(s, o+32, z + w[1], y + load8(s, o+16))
+    swap z, x
+    inc o, 64
+    if o == eos: break
+  let mul = k1 + ((z and 0xff) shl 1)
+  o = last64
+  w[0] += (s.lenU - 1) and 63
+  v[0] += w[0]
+  w[0] += v[0]
+  x = rotR(x + y + v[0] + load8(s, o+8), 37)*mul
+  y = rotR(y + v[1] + load8(s, o+48), 42)*mul
+  x = x xor w[1]*9
+  y += v[0]*9 + load8(s, o+40)
+  z = rotR(z + w[0], 33)*mul
+  v = weakLen32withSeeds(s, o+0 , v[1]*mul, x + w[0])
+  w = weakLen32withSeeds(s, o+32, z + w[1], y + load8(s, o+16))
+  swap z, x
+  len16 len16(v[0],w[0],mul) + shiftMix(y)*k0 + z, len16(v[1],w[1],mul) + x, mul
+
+template jsNoInt64: untyped =
+  when defined js:
+    when compiles(compileOption("jsbigint64")):
+      when not compileOption("jsbigint64"): true
+      else: false
+    else: false
+  else: false
+const sHash2 = (when defined(nimStringHash2) or jsNoInt64(): true else: false)
+
+template maybeFailJS_Number =
+  when jsNoInt64() and not defined(nimStringHash2):
+    {.error: "Must use `-d:nimStringHash2` when using `--jsbigint64:off`".}
+
 proc hash*(x: string): Hash =
   ## Efficient hashing of strings.
   ##
@@ -387,11 +539,14 @@ proc hash*(x: string): Hash =
   ## * `hashIgnoreCase <#hashIgnoreCase,string>`_
   runnableExamples:
     doAssert hash("abracadabra") != hash("AbracadabrA")
-
-  when nimvm:
-    result = hashVmImpl(x, 0, high(x))
+  maybeFailJS_Number()
+  when not sHash2:
+    result = cast[Hash](hashFarm(toOpenArrayByte(x, 0, x.high)))
   else:
-    result = murmurHash(toOpenArrayByte(x, 0, high(x)))
+    #when nimvm:
+    #  result = hashVmImpl(x, 0, high(x))
+    when true:
+      result = murmurHash(toOpenArrayByte(x, 0, high(x)))
 
 proc hash*(x: cstring): Hash =
   ## Efficient hashing of null-terminated strings.
@@ -400,14 +555,22 @@ proc hash*(x: cstring): Hash =
     doAssert hash(cstring"AbracadabrA") == hash("AbracadabrA")
     doAssert hash(cstring"abracadabra") != hash(cstring"AbracadabrA")
 
-  when nimvm:
-    hashVmImpl(x, 0, high(x))
-  else:
-    when not defined(js):
-      murmurHash(toOpenArrayByte(x, 0, x.high))
-    else:
+  maybeFailJS_Number()
+  when not sHash2:
+    when defined js:
       let xx = $x
-      murmurHash(toOpenArrayByte(xx, 0, high(xx)))
+      result = cast[Hash](hashFarm(toOpenArrayByte(xx, 0, xx.high)))
+    else:
+      result = cast[Hash](hashFarm(toOpenArrayByte(x, 0, x.high)))
+  else:
+    #when nimvm:
+    #  result = hashVmImpl(x, 0, high(x))
+    when true:
+      when not defined(js):
+        result = murmurHash(toOpenArrayByte(x, 0, x.high))
+      else:
+        let xx = $x
+        result = murmurHash(toOpenArrayByte(xx, 0, high(xx)))
 
 proc hash*(sBuf: string, sPos, ePos: int): Hash =
   ## Efficient hashing of a string buffer, from starting
@@ -418,7 +581,11 @@ proc hash*(sBuf: string, sPos, ePos: int): Hash =
     var a = "abracadabra"
     doAssert hash(a, 0, 3) == hash(a, 7, 10)
 
-  murmurHash(toOpenArrayByte(sBuf, sPos, ePos))
+  maybeFailJS_Number()
+  when not sHash2:
+    result = cast[Hash](hashFarm(toOpenArrayByte(sBuf, sPos, ePos)))
+  else:
+    murmurHash(toOpenArrayByte(sBuf, sPos, ePos))
 
 proc hashIgnoreStyle*(x: string): Hash =
   ## Efficient hashing of strings; style is ignored.
@@ -553,12 +720,18 @@ proc hash*[A](x: openArray[A]): Hash =
   ## Efficient hashing of arrays and sequences.
   ## There must be a `hash` proc defined for the element type `A`.
   when A is byte:
-    result = murmurHash(x)
+    when not sHash2:
+      result = cast[Hash](hashFarm(x))
+    else:
+      result = murmurHash(x)
   elif A is char:
-    when nimvm:
-      result = hashVmImplChar(x, 0, x.high)
+    when not sHash2:
+      result = cast[Hash](hashFarm(toOpenArrayByte(x, 0, x.high)))
     else:
-      result = murmurHash(toOpenArrayByte(x, 0, x.high))
+      #when nimvm:
+      #  result = hashVmImplChar(x, 0, x.high)
+      when true:
+        result = murmurHash(toOpenArrayByte(x, 0, x.high))
   else:
     result = 0
     for a in x:
@@ -574,17 +747,24 @@ proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash =
   runnableExamples:
     let a = [1, 2, 5, 1, 2, 6]
     doAssert hash(a, 0, 1) == hash(a, 3, 4)
-
   when A is byte:
-    when nimvm:
-      result = hashVmImplByte(aBuf, sPos, ePos)
+    maybeFailJS_Number()
+    when not sHash2:
+      result = cast[Hash](hashFarm(toOpenArray(aBuf, sPos, ePos)))
     else:
-      result = murmurHash(toOpenArray(aBuf, sPos, ePos))
+      #when nimvm:
+      #  result = hashVmImplByte(aBuf, sPos, ePos)
+      when true:
+        result = murmurHash(toOpenArray(aBuf, sPos, ePos))
   elif A is char:
-    when nimvm:
-      result = hashVmImplChar(aBuf, sPos, ePos)
+    maybeFailJS_Number()
+    when not sHash2:
+      result = cast[Hash](hashFarm(toOpenArrayByte(aBuf, sPos, ePos)))
     else:
-      result = murmurHash(toOpenArrayByte(aBuf, sPos, ePos))
+      #when nimvm:
+      #  result = hashVmImplChar(aBuf, sPos, ePos)
+      when true:
+        result = murmurHash(toOpenArrayByte(aBuf, sPos, ePos))
   else:
     for i in sPos .. ePos:
       result = result !& hash(aBuf[i])
diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim
index 45365c185..5ccab379c 100644
--- a/lib/pure/httpcore.nim
+++ b/lib/pure/httpcore.nim
@@ -164,7 +164,8 @@ func `[]`*(headers: HttpHeaders, key: string): HttpHeaderValues =
   ## To access multiple values of a key, use the overloaded `[]` below or
   ## to get all of them access the `table` field directly.
   {.cast(noSideEffect).}:
-    return headers.table[headers.toCaseInsensitive(key)].HttpHeaderValues
+    let tmp = headers.table[headers.toCaseInsensitive(key)]
+    return HttpHeaderValues(tmp)
 
 converter toString*(values: HttpHeaderValues): string =
   return seq[string](values)[0]
diff --git a/lib/pure/includes/unicode_ranges.nim b/lib/pure/includes/unicode_ranges.nim
index 5bb22bd8b..04ccfb747 100644
--- a/lib/pure/includes/unicode_ranges.nim
+++ b/lib/pure/includes/unicode_ranges.nim
@@ -2,1988 +2,1979 @@
 
 const
   toLowerRanges = [
-    0x00041'i32, 0x0005A, 532,
-    0x000C0, 0x000D6, 532,
-    0x000D8, 0x000DE, 532,
-    0x00189, 0x0018A, 705,
-    0x001B1, 0x001B2, 717,
-    0x00388, 0x0038A, 537,
-    0x0038E, 0x0038F, 563,
-    0x00391, 0x003A1, 532,
-    0x003A3, 0x003AB, 532,
-    0x003FD, 0x003FF, 370,
-    0x00400, 0x0040F, 580,
-    0x00410, 0x0042F, 532,
-    0x00531, 0x00556, 548,
-    0x010A0, 0x010C5, 7764,
-    0x013A0, 0x013EF, 39364,
-    0x013F0, 0x013F5, 508,
-    0x01C90, 0x01CBA, -2508,
-    0x01CBD, 0x01CBF, -2508,
-    0x01F08, 0x01F0F, 492,
-    0x01F18, 0x01F1D, 492,
-    0x01F28, 0x01F2F, 492,
-    0x01F38, 0x01F3F, 492,
-    0x01F48, 0x01F4D, 492,
-    0x01F68, 0x01F6F, 492,
-    0x01F88, 0x01F8F, 492,
-    0x01F98, 0x01F9F, 492,
-    0x01FA8, 0x01FAF, 492,
-    0x01FB8, 0x01FB9, 492,
-    0x01FBA, 0x01FBB, 426,
-    0x01FC8, 0x01FCB, 414,
-    0x01FD8, 0x01FD9, 492,
-    0x01FDA, 0x01FDB, 400,
-    0x01FE8, 0x01FE9, 492,
-    0x01FEA, 0x01FEB, 388,
-    0x01FF8, 0x01FF9, 372,
-    0x01FFA, 0x01FFB, 374,
-    0x02C00, 0x02C2E, 548,
-    0x02C7E, 0x02C7F, -10315,
-    0x0FF21, 0x0FF3A, 532,
-    0x10400, 0x10427, 540,
-    0x104B0, 0x104D3, 540,
-    0x10C80, 0x10CB2, 564,
-    0x118A0, 0x118BF, 532,
-    0x16E40, 0x16E5F, 532,
-    0x1E900, 0x1E921, 534,
+    0x00041'i32, 0x0005A'i32, 532,
+    0x000C0'i32, 0x000D6'i32, 532,
+    0x000D8'i32, 0x000DE'i32, 532,
+    0x00189'i32, 0x0018A'i32, 705,
+    0x001B1'i32, 0x001B2'i32, 717,
+    0x00388'i32, 0x0038A'i32, 537,
+    0x0038E'i32, 0x0038F'i32, 563,
+    0x00391'i32, 0x003A1'i32, 532,
+    0x003A3'i32, 0x003AB'i32, 532,
+    0x003FD'i32, 0x003FF'i32, 370,
+    0x00400'i32, 0x0040F'i32, 580,
+    0x00410'i32, 0x0042F'i32, 532,
+    0x00531'i32, 0x00556'i32, 548,
+    0x010A0'i32, 0x010C5'i32, 7764,
+    0x013A0'i32, 0x013EF'i32, 39364,
+    0x013F0'i32, 0x013F5'i32, 508,
+    0x01C90'i32, 0x01CBA'i32, -2508,
+    0x01CBD'i32, 0x01CBF'i32, -2508,
+    0x01F08'i32, 0x01F0F'i32, 492,
+    0x01F18'i32, 0x01F1D'i32, 492,
+    0x01F28'i32, 0x01F2F'i32, 492,
+    0x01F38'i32, 0x01F3F'i32, 492,
+    0x01F48'i32, 0x01F4D'i32, 492,
+    0x01F68'i32, 0x01F6F'i32, 492,
+    0x01F88'i32, 0x01F8F'i32, 492,
+    0x01F98'i32, 0x01F9F'i32, 492,
+    0x01FA8'i32, 0x01FAF'i32, 492,
+    0x01FB8'i32, 0x01FB9'i32, 492,
+    0x01FBA'i32, 0x01FBB'i32, 426,
+    0x01FC8'i32, 0x01FCB'i32, 414,
+    0x01FD8'i32, 0x01FD9'i32, 492,
+    0x01FDA'i32, 0x01FDB'i32, 400,
+    0x01FE8'i32, 0x01FE9'i32, 492,
+    0x01FEA'i32, 0x01FEB'i32, 388,
+    0x01FF8'i32, 0x01FF9'i32, 372,
+    0x01FFA'i32, 0x01FFB'i32, 374,
+    0x02C00'i32, 0x02C2E'i32, 548,
+    0x02C7E'i32, 0x02C7F'i32, -10315,
+    0x0FF21'i32, 0x0FF3A'i32, 532,
+    0x10400'i32, 0x10427'i32, 540,
+    0x104B0'i32, 0x104D3'i32, 540,
+    0x10C80'i32, 0x10CB2'i32, 564,
+    0x118A0'i32, 0x118BF'i32, 532,
+    0x16E40'i32, 0x16E5F'i32, 532,
+    0x1E900'i32, 0x1E921'i32, 534,
   ]
 
   toLowerSinglets = [
     0x00100'i32, 501,
-    0x00102, 501,
-    0x00104, 501,
-    0x00106, 501,
-    0x00108, 501,
-    0x0010A, 501,
-    0x0010C, 501,
-    0x0010E, 501,
-    0x00110, 501,
-    0x00112, 501,
-    0x00114, 501,
-    0x00116, 501,
-    0x00118, 501,
-    0x0011A, 501,
-    0x0011C, 501,
-    0x0011E, 501,
-    0x00120, 501,
-    0x00122, 501,
-    0x00124, 501,
-    0x00126, 501,
-    0x00128, 501,
-    0x0012A, 501,
-    0x0012C, 501,
-    0x0012E, 501,
-    0x00130, 301,
-    0x00132, 501,
-    0x00134, 501,
-    0x00136, 501,
-    0x00139, 501,
-    0x0013B, 501,
-    0x0013D, 501,
-    0x0013F, 501,
-    0x00141, 501,
-    0x00143, 501,
-    0x00145, 501,
-    0x00147, 501,
-    0x0014A, 501,
-    0x0014C, 501,
-    0x0014E, 501,
-    0x00150, 501,
-    0x00152, 501,
-    0x00154, 501,
-    0x00156, 501,
-    0x00158, 501,
-    0x0015A, 501,
-    0x0015C, 501,
-    0x0015E, 501,
-    0x00160, 501,
-    0x00162, 501,
-    0x00164, 501,
-    0x00166, 501,
-    0x00168, 501,
-    0x0016A, 501,
-    0x0016C, 501,
-    0x0016E, 501,
-    0x00170, 501,
-    0x00172, 501,
-    0x00174, 501,
-    0x00176, 501,
-    0x00178, 379,
-    0x00179, 501,
-    0x0017B, 501,
-    0x0017D, 501,
-    0x00181, 710,
-    0x00182, 501,
-    0x00184, 501,
-    0x00186, 706,
-    0x00187, 501,
-    0x0018B, 501,
-    0x0018E, 579,
-    0x0018F, 702,
-    0x00190, 703,
-    0x00191, 501,
-    0x00193, 705,
-    0x00194, 707,
-    0x00196, 711,
-    0x00197, 709,
-    0x00198, 501,
-    0x0019C, 711,
-    0x0019D, 713,
-    0x0019F, 714,
-    0x001A0, 501,
-    0x001A2, 501,
-    0x001A4, 501,
-    0x001A6, 718,
-    0x001A7, 501,
-    0x001A9, 718,
-    0x001AC, 501,
-    0x001AE, 718,
-    0x001AF, 501,
-    0x001B3, 501,
-    0x001B5, 501,
-    0x001B7, 719,
-    0x001B8, 501,
-    0x001BC, 501,
-    0x001C4, 502,
-    0x001C5, 501,
-    0x001C7, 502,
-    0x001C8, 501,
-    0x001CA, 502,
-    0x001CB, 501,
-    0x001CD, 501,
-    0x001CF, 501,
-    0x001D1, 501,
-    0x001D3, 501,
-    0x001D5, 501,
-    0x001D7, 501,
-    0x001D9, 501,
-    0x001DB, 501,
-    0x001DE, 501,
-    0x001E0, 501,
-    0x001E2, 501,
-    0x001E4, 501,
-    0x001E6, 501,
-    0x001E8, 501,
-    0x001EA, 501,
-    0x001EC, 501,
-    0x001EE, 501,
-    0x001F1, 502,
-    0x001F2, 501,
-    0x001F4, 501,
-    0x001F6, 403,
-    0x001F7, 444,
-    0x001F8, 501,
-    0x001FA, 501,
-    0x001FC, 501,
-    0x001FE, 501,
-    0x00200, 501,
-    0x00202, 501,
-    0x00204, 501,
-    0x00206, 501,
-    0x00208, 501,
-    0x0020A, 501,
-    0x0020C, 501,
-    0x0020E, 501,
-    0x00210, 501,
-    0x00212, 501,
-    0x00214, 501,
-    0x00216, 501,
-    0x00218, 501,
-    0x0021A, 501,
-    0x0021C, 501,
-    0x0021E, 501,
-    0x00220, 370,
-    0x00222, 501,
-    0x00224, 501,
-    0x00226, 501,
-    0x00228, 501,
-    0x0022A, 501,
-    0x0022C, 501,
-    0x0022E, 501,
-    0x00230, 501,
-    0x00232, 501,
-    0x0023A, 11295,
-    0x0023B, 501,
-    0x0023D, 337,
-    0x0023E, 11292,
-    0x00241, 501,
-    0x00243, 305,
-    0x00244, 569,
-    0x00245, 571,
-    0x00246, 501,
-    0x00248, 501,
-    0x0024A, 501,
-    0x0024C, 501,
-    0x0024E, 501,
-    0x00370, 501,
-    0x00372, 501,
-    0x00376, 501,
-    0x0037F, 616,
-    0x00386, 538,
-    0x0038C, 564,
-    0x003CF, 508,
-    0x003D8, 501,
-    0x003DA, 501,
-    0x003DC, 501,
-    0x003DE, 501,
-    0x003E0, 501,
-    0x003E2, 501,
-    0x003E4, 501,
-    0x003E6, 501,
-    0x003E8, 501,
-    0x003EA, 501,
-    0x003EC, 501,
-    0x003EE, 501,
-    0x003F4, 440,
-    0x003F7, 501,
-    0x003F9, 493,
-    0x003FA, 501,
-    0x00460, 501,
-    0x00462, 501,
-    0x00464, 501,
-    0x00466, 501,
-    0x00468, 501,
-    0x0046A, 501,
-    0x0046C, 501,
-    0x0046E, 501,
-    0x00470, 501,
-    0x00472, 501,
-    0x00474, 501,
-    0x00476, 501,
-    0x00478, 501,
-    0x0047A, 501,
-    0x0047C, 501,
-    0x0047E, 501,
-    0x00480, 501,
-    0x0048A, 501,
-    0x0048C, 501,
-    0x0048E, 501,
-    0x00490, 501,
-    0x00492, 501,
-    0x00494, 501,
-    0x00496, 501,
-    0x00498, 501,
-    0x0049A, 501,
-    0x0049C, 501,
-    0x0049E, 501,
-    0x004A0, 501,
-    0x004A2, 501,
-    0x004A4, 501,
-    0x004A6, 501,
-    0x004A8, 501,
-    0x004AA, 501,
-    0x004AC, 501,
-    0x004AE, 501,
-    0x004B0, 501,
-    0x004B2, 501,
-    0x004B4, 501,
-    0x004B6, 501,
-    0x004B8, 501,
-    0x004BA, 501,
-    0x004BC, 501,
-    0x004BE, 501,
-    0x004C0, 515,
-    0x004C1, 501,
-    0x004C3, 501,
-    0x004C5, 501,
-    0x004C7, 501,
-    0x004C9, 501,
-    0x004CB, 501,
-    0x004CD, 501,
-    0x004D0, 501,
-    0x004D2, 501,
-    0x004D4, 501,
-    0x004D6, 501,
-    0x004D8, 501,
-    0x004DA, 501,
-    0x004DC, 501,
-    0x004DE, 501,
-    0x004E0, 501,
-    0x004E2, 501,
-    0x004E4, 501,
-    0x004E6, 501,
-    0x004E8, 501,
-    0x004EA, 501,
-    0x004EC, 501,
-    0x004EE, 501,
-    0x004F0, 501,
-    0x004F2, 501,
-    0x004F4, 501,
-    0x004F6, 501,
-    0x004F8, 501,
-    0x004FA, 501,
-    0x004FC, 501,
-    0x004FE, 501,
-    0x00500, 501,
-    0x00502, 501,
-    0x00504, 501,
-    0x00506, 501,
-    0x00508, 501,
-    0x0050A, 501,
-    0x0050C, 501,
-    0x0050E, 501,
-    0x00510, 501,
-    0x00512, 501,
-    0x00514, 501,
-    0x00516, 501,
-    0x00518, 501,
-    0x0051A, 501,
-    0x0051C, 501,
-    0x0051E, 501,
-    0x00520, 501,
-    0x00522, 501,
-    0x00524, 501,
-    0x00526, 501,
-    0x00528, 501,
-    0x0052A, 501,
-    0x0052C, 501,
-    0x0052E, 501,
-    0x010C7, 7764,
-    0x010CD, 7764,
-    0x01E00, 501,
-    0x01E02, 501,
-    0x01E04, 501,
-    0x01E06, 501,
-    0x01E08, 501,
-    0x01E0A, 501,
-    0x01E0C, 501,
-    0x01E0E, 501,
-    0x01E10, 501,
-    0x01E12, 501,
-    0x01E14, 501,
-    0x01E16, 501,
-    0x01E18, 501,
-    0x01E1A, 501,
-    0x01E1C, 501,
-    0x01E1E, 501,
-    0x01E20, 501,
-    0x01E22, 501,
-    0x01E24, 501,
-    0x01E26, 501,
-    0x01E28, 501,
-    0x01E2A, 501,
-    0x01E2C, 501,
-    0x01E2E, 501,
-    0x01E30, 501,
-    0x01E32, 501,
-    0x01E34, 501,
-    0x01E36, 501,
-    0x01E38, 501,
-    0x01E3A, 501,
-    0x01E3C, 501,
-    0x01E3E, 501,
-    0x01E40, 501,
-    0x01E42, 501,
-    0x01E44, 501,
-    0x01E46, 501,
-    0x01E48, 501,
-    0x01E4A, 501,
-    0x01E4C, 501,
-    0x01E4E, 501,
-    0x01E50, 501,
-    0x01E52, 501,
-    0x01E54, 501,
-    0x01E56, 501,
-    0x01E58, 501,
-    0x01E5A, 501,
-    0x01E5C, 501,
-    0x01E5E, 501,
-    0x01E60, 501,
-    0x01E62, 501,
-    0x01E64, 501,
-    0x01E66, 501,
-    0x01E68, 501,
-    0x01E6A, 501,
-    0x01E6C, 501,
-    0x01E6E, 501,
-    0x01E70, 501,
-    0x01E72, 501,
-    0x01E74, 501,
-    0x01E76, 501,
-    0x01E78, 501,
-    0x01E7A, 501,
-    0x01E7C, 501,
-    0x01E7E, 501,
-    0x01E80, 501,
-    0x01E82, 501,
-    0x01E84, 501,
-    0x01E86, 501,
-    0x01E88, 501,
-    0x01E8A, 501,
-    0x01E8C, 501,
-    0x01E8E, 501,
-    0x01E90, 501,
-    0x01E92, 501,
-    0x01E94, 501,
-    0x01E9E, -7115,
-    0x01EA0, 501,
-    0x01EA2, 501,
-    0x01EA4, 501,
-    0x01EA6, 501,
-    0x01EA8, 501,
-    0x01EAA, 501,
-    0x01EAC, 501,
-    0x01EAE, 501,
-    0x01EB0, 501,
-    0x01EB2, 501,
-    0x01EB4, 501,
-    0x01EB6, 501,
-    0x01EB8, 501,
-    0x01EBA, 501,
-    0x01EBC, 501,
-    0x01EBE, 501,
-    0x01EC0, 501,
-    0x01EC2, 501,
-    0x01EC4, 501,
-    0x01EC6, 501,
-    0x01EC8, 501,
-    0x01ECA, 501,
-    0x01ECC, 501,
-    0x01ECE, 501,
-    0x01ED0, 501,
-    0x01ED2, 501,
-    0x01ED4, 501,
-    0x01ED6, 501,
-    0x01ED8, 501,
-    0x01EDA, 501,
-    0x01EDC, 501,
-    0x01EDE, 501,
-    0x01EE0, 501,
-    0x01EE2, 501,
-    0x01EE4, 501,
-    0x01EE6, 501,
-    0x01EE8, 501,
-    0x01EEA, 501,
-    0x01EEC, 501,
-    0x01EEE, 501,
-    0x01EF0, 501,
-    0x01EF2, 501,
-    0x01EF4, 501,
-    0x01EF6, 501,
-    0x01EF8, 501,
-    0x01EFA, 501,
-    0x01EFC, 501,
-    0x01EFE, 501,
-    0x01F59, 492,
-    0x01F5B, 492,
-    0x01F5D, 492,
-    0x01F5F, 492,
-    0x01FBC, 491,
-    0x01FCC, 491,
-    0x01FEC, 493,
-    0x01FFC, 491,
-    0x02126, -7017,
-    0x0212A, -7883,
-    0x0212B, -7762,
-    0x02132, 528,
-    0x02183, 501,
-    0x02C60, 501,
-    0x02C62, -10243,
-    0x02C63, -3314,
-    0x02C64, -10227,
-    0x02C67, 501,
-    0x02C69, 501,
-    0x02C6B, 501,
-    0x02C6D, -10280,
-    0x02C6E, -10249,
-    0x02C6F, -10283,
-    0x02C70, -10282,
-    0x02C72, 501,
-    0x02C75, 501,
-    0x02C80, 501,
-    0x02C82, 501,
-    0x02C84, 501,
-    0x02C86, 501,
-    0x02C88, 501,
-    0x02C8A, 501,
-    0x02C8C, 501,
-    0x02C8E, 501,
-    0x02C90, 501,
-    0x02C92, 501,
-    0x02C94, 501,
-    0x02C96, 501,
-    0x02C98, 501,
-    0x02C9A, 501,
-    0x02C9C, 501,
-    0x02C9E, 501,
-    0x02CA0, 501,
-    0x02CA2, 501,
-    0x02CA4, 501,
-    0x02CA6, 501,
-    0x02CA8, 501,
-    0x02CAA, 501,
-    0x02CAC, 501,
-    0x02CAE, 501,
-    0x02CB0, 501,
-    0x02CB2, 501,
-    0x02CB4, 501,
-    0x02CB6, 501,
-    0x02CB8, 501,
-    0x02CBA, 501,
-    0x02CBC, 501,
-    0x02CBE, 501,
-    0x02CC0, 501,
-    0x02CC2, 501,
-    0x02CC4, 501,
-    0x02CC6, 501,
-    0x02CC8, 501,
-    0x02CCA, 501,
-    0x02CCC, 501,
-    0x02CCE, 501,
-    0x02CD0, 501,
-    0x02CD2, 501,
-    0x02CD4, 501,
-    0x02CD6, 501,
-    0x02CD8, 501,
-    0x02CDA, 501,
-    0x02CDC, 501,
-    0x02CDE, 501,
-    0x02CE0, 501,
-    0x02CE2, 501,
-    0x02CEB, 501,
-    0x02CED, 501,
-    0x02CF2, 501,
-    0x0A640, 501,
-    0x0A642, 501,
-    0x0A644, 501,
-    0x0A646, 501,
-    0x0A648, 501,
-    0x0A64A, 501,
-    0x0A64C, 501,
-    0x0A64E, 501,
-    0x0A650, 501,
-    0x0A652, 501,
-    0x0A654, 501,
-    0x0A656, 501,
-    0x0A658, 501,
-    0x0A65A, 501,
-    0x0A65C, 501,
-    0x0A65E, 501,
-    0x0A660, 501,
-    0x0A662, 501,
-    0x0A664, 501,
-    0x0A666, 501,
-    0x0A668, 501,
-    0x0A66A, 501,
-    0x0A66C, 501,
-    0x0A680, 501,
-    0x0A682, 501,
-    0x0A684, 501,
-    0x0A686, 501,
-    0x0A688, 501,
-    0x0A68A, 501,
-    0x0A68C, 501,
-    0x0A68E, 501,
-    0x0A690, 501,
-    0x0A692, 501,
-    0x0A694, 501,
-    0x0A696, 501,
-    0x0A698, 501,
-    0x0A69A, 501,
-    0x0A722, 501,
-    0x0A724, 501,
-    0x0A726, 501,
-    0x0A728, 501,
-    0x0A72A, 501,
-    0x0A72C, 501,
-    0x0A72E, 501,
-    0x0A732, 501,
-    0x0A734, 501,
-    0x0A736, 501,
-    0x0A738, 501,
-    0x0A73A, 501,
-    0x0A73C, 501,
-    0x0A73E, 501,
-    0x0A740, 501,
-    0x0A742, 501,
-    0x0A744, 501,
-    0x0A746, 501,
-    0x0A748, 501,
-    0x0A74A, 501,
-    0x0A74C, 501,
-    0x0A74E, 501,
-    0x0A750, 501,
-    0x0A752, 501,
-    0x0A754, 501,
-    0x0A756, 501,
-    0x0A758, 501,
-    0x0A75A, 501,
-    0x0A75C, 501,
-    0x0A75E, 501,
-    0x0A760, 501,
-    0x0A762, 501,
-    0x0A764, 501,
-    0x0A766, 501,
-    0x0A768, 501,
-    0x0A76A, 501,
-    0x0A76C, 501,
-    0x0A76E, 501,
-    0x0A779, 501,
-    0x0A77B, 501,
-    0x0A77D, -34832,
-    0x0A77E, 501,
-    0x0A780, 501,
-    0x0A782, 501,
-    0x0A784, 501,
-    0x0A786, 501,
-    0x0A78B, 501,
-    0x0A78D, -41780,
-    0x0A790, 501,
-    0x0A792, 501,
-    0x0A796, 501,
-    0x0A798, 501,
-    0x0A79A, 501,
-    0x0A79C, 501,
-    0x0A79E, 501,
-    0x0A7A0, 501,
-    0x0A7A2, 501,
-    0x0A7A4, 501,
-    0x0A7A6, 501,
-    0x0A7A8, 501,
-    0x0A7AA, -41808,
-    0x0A7AB, -41819,
-    0x0A7AC, -41815,
-    0x0A7AD, -41805,
-    0x0A7AE, -41808,
-    0x0A7B0, -41758,
-    0x0A7B1, -41782,
-    0x0A7B2, -41761,
-    0x0A7B3, 1428,
-    0x0A7B4, 501,
-    0x0A7B6, 501,
-    0x0A7B8, 501,
-    0x0A7BA, 501,
-    0x0A7BC, 501,
-    0x0A7BE, 501,
-    0x0A7C2, 501,
-    0x0A7C4, 452,
-    0x0A7C5, -41807,
-    0x0A7C6, -34884,
+    0x00102'i32, 501,
+    0x00104'i32, 501,
+    0x00106'i32, 501,
+    0x00108'i32, 501,
+    0x0010A'i32, 501,
+    0x0010C'i32, 501,
+    0x0010E'i32, 501,
+    0x00110'i32, 501,
+    0x00112'i32, 501,
+    0x00114'i32, 501,
+    0x00116'i32, 501,
+    0x00118'i32, 501,
+    0x0011A'i32, 501,
+    0x0011C'i32, 501,
+    0x0011E'i32, 501,
+    0x00120'i32, 501,
+    0x00122'i32, 501,
+    0x00124'i32, 501,
+    0x00126'i32, 501,
+    0x00128'i32, 501,
+    0x0012A'i32, 501,
+    0x0012C'i32, 501,
+    0x0012E'i32, 501,
+    0x00130'i32, 301,
+    0x00132'i32, 501,
+    0x00134'i32, 501,
+    0x00136'i32, 501,
+    0x00139'i32, 501,
+    0x0013B'i32, 501,
+    0x0013D'i32, 501,
+    0x0013F'i32, 501,
+    0x00141'i32, 501,
+    0x00143'i32, 501,
+    0x00145'i32, 501,
+    0x00147'i32, 501,
+    0x0014A'i32, 501,
+    0x0014C'i32, 501,
+    0x0014E'i32, 501,
+    0x00150'i32, 501,
+    0x00152'i32, 501,
+    0x00154'i32, 501,
+    0x00156'i32, 501,
+    0x00158'i32, 501,
+    0x0015A'i32, 501,
+    0x0015C'i32, 501,
+    0x0015E'i32, 501,
+    0x00160'i32, 501,
+    0x00162'i32, 501,
+    0x00164'i32, 501,
+    0x00166'i32, 501,
+    0x00168'i32, 501,
+    0x0016A'i32, 501,
+    0x0016C'i32, 501,
+    0x0016E'i32, 501,
+    0x00170'i32, 501,
+    0x00172'i32, 501,
+    0x00174'i32, 501,
+    0x00176'i32, 501,
+    0x00178'i32, 379,
+    0x00179'i32, 501,
+    0x0017B'i32, 501,
+    0x0017D'i32, 501,
+    0x00181'i32, 710,
+    0x00182'i32, 501,
+    0x00184'i32, 501,
+    0x00186'i32, 706,
+    0x00187'i32, 501,
+    0x0018B'i32, 501,
+    0x0018E'i32, 579,
+    0x0018F'i32, 702,
+    0x00190'i32, 703,
+    0x00191'i32, 501,
+    0x00193'i32, 705,
+    0x00194'i32, 707,
+    0x00196'i32, 711,
+    0x00197'i32, 709,
+    0x00198'i32, 501,
+    0x0019C'i32, 711,
+    0x0019D'i32, 713,
+    0x0019F'i32, 714,
+    0x001A0'i32, 501,
+    0x001A2'i32, 501,
+    0x001A4'i32, 501,
+    0x001A6'i32, 718,
+    0x001A7'i32, 501,
+    0x001A9'i32, 718,
+    0x001AC'i32, 501,
+    0x001AE'i32, 718,
+    0x001AF'i32, 501,
+    0x001B3'i32, 501,
+    0x001B5'i32, 501,
+    0x001B7'i32, 719,
+    0x001B8'i32, 501,
+    0x001BC'i32, 501,
+    0x001C4'i32, 502,
+    0x001C5'i32, 501,
+    0x001C7'i32, 502,
+    0x001C8'i32, 501,
+    0x001CA'i32, 502,
+    0x001CB'i32, 501,
+    0x001CD'i32, 501,
+    0x001CF'i32, 501,
+    0x001D1'i32, 501,
+    0x001D3'i32, 501,
+    0x001D5'i32, 501,
+    0x001D7'i32, 501,
+    0x001D9'i32, 501,
+    0x001DB'i32, 501,
+    0x001DE'i32, 501,
+    0x001E0'i32, 501,
+    0x001E2'i32, 501,
+    0x001E4'i32, 501,
+    0x001E6'i32, 501,
+    0x001E8'i32, 501,
+    0x001EA'i32, 501,
+    0x001EC'i32, 501,
+    0x001EE'i32, 501,
+    0x001F1'i32, 502,
+    0x001F2'i32, 501,
+    0x001F4'i32, 501,
+    0x001F6'i32, 403,
+    0x001F7'i32, 444,
+    0x001F8'i32, 501,
+    0x001FA'i32, 501,
+    0x001FC'i32, 501,
+    0x001FE'i32, 501,
+    0x00200'i32, 501,
+    0x00202'i32, 501,
+    0x00204'i32, 501,
+    0x00206'i32, 501,
+    0x00208'i32, 501,
+    0x0020A'i32, 501,
+    0x0020C'i32, 501,
+    0x0020E'i32, 501,
+    0x00210'i32, 501,
+    0x00212'i32, 501,
+    0x00214'i32, 501,
+    0x00216'i32, 501,
+    0x00218'i32, 501,
+    0x0021A'i32, 501,
+    0x0021C'i32, 501,
+    0x0021E'i32, 501,
+    0x00220'i32, 370,
+    0x00222'i32, 501,
+    0x00224'i32, 501,
+    0x00226'i32, 501,
+    0x00228'i32, 501,
+    0x0022A'i32, 501,
+    0x0022C'i32, 501,
+    0x0022E'i32, 501,
+    0x00230'i32, 501,
+    0x00232'i32, 501,
+    0x0023A'i32, 11295,
+    0x0023B'i32, 501,
+    0x0023D'i32, 337,
+    0x0023E'i32, 11292,
+    0x00241'i32, 501,
+    0x00243'i32, 305,
+    0x00244'i32, 569,
+    0x00245'i32, 571,
+    0x00246'i32, 501,
+    0x00248'i32, 501,
+    0x0024A'i32, 501,
+    0x0024C'i32, 501,
+    0x0024E'i32, 501,
+    0x00370'i32, 501,
+    0x00372'i32, 501,
+    0x00376'i32, 501,
+    0x0037F'i32, 616,
+    0x00386'i32, 538,
+    0x0038C'i32, 564,
+    0x003CF'i32, 508,
+    0x003D8'i32, 501,
+    0x003DA'i32, 501,
+    0x003DC'i32, 501,
+    0x003DE'i32, 501,
+    0x003E0'i32, 501,
+    0x003E2'i32, 501,
+    0x003E4'i32, 501,
+    0x003E6'i32, 501,
+    0x003E8'i32, 501,
+    0x003EA'i32, 501,
+    0x003EC'i32, 501,
+    0x003EE'i32, 501,
+    0x003F4'i32, 440,
+    0x003F7'i32, 501,
+    0x003F9'i32, 493,
+    0x003FA'i32, 501,
+    0x00460'i32, 501,
+    0x00462'i32, 501,
+    0x00464'i32, 501,
+    0x00466'i32, 501,
+    0x00468'i32, 501,
+    0x0046A'i32, 501,
+    0x0046C'i32, 501,
+    0x0046E'i32, 501,
+    0x00470'i32, 501,
+    0x00472'i32, 501,
+    0x00474'i32, 501,
+    0x00476'i32, 501,
+    0x00478'i32, 501,
+    0x0047A'i32, 501,
+    0x0047C'i32, 501,
+    0x0047E'i32, 501,
+    0x00480'i32, 501,
+    0x0048A'i32, 501,
+    0x0048C'i32, 501,
+    0x0048E'i32, 501,
+    0x00490'i32, 501,
+    0x00492'i32, 501,
+    0x00494'i32, 501,
+    0x00496'i32, 501,
+    0x00498'i32, 501,
+    0x0049A'i32, 501,
+    0x0049C'i32, 501,
+    0x0049E'i32, 501,
+    0x004A0'i32, 501,
+    0x004A2'i32, 501,
+    0x004A4'i32, 501,
+    0x004A6'i32, 501,
+    0x004A8'i32, 501,
+    0x004AA'i32, 501,
+    0x004AC'i32, 501,
+    0x004AE'i32, 501,
+    0x004B0'i32, 501,
+    0x004B2'i32, 501,
+    0x004B4'i32, 501,
+    0x004B6'i32, 501,
+    0x004B8'i32, 501,
+    0x004BA'i32, 501,
+    0x004BC'i32, 501,
+    0x004BE'i32, 501,
+    0x004C0'i32, 515,
+    0x004C1'i32, 501,
+    0x004C3'i32, 501,
+    0x004C5'i32, 501,
+    0x004C7'i32, 501,
+    0x004C9'i32, 501,
+    0x004CB'i32, 501,
+    0x004CD'i32, 501,
+    0x004D0'i32, 501,
+    0x004D2'i32, 501,
+    0x004D4'i32, 501,
+    0x004D6'i32, 501,
+    0x004D8'i32, 501,
+    0x004DA'i32, 501,
+    0x004DC'i32, 501,
+    0x004DE'i32, 501,
+    0x004E0'i32, 501,
+    0x004E2'i32, 501,
+    0x004E4'i32, 501,
+    0x004E6'i32, 501,
+    0x004E8'i32, 501,
+    0x004EA'i32, 501,
+    0x004EC'i32, 501,
+    0x004EE'i32, 501,
+    0x004F0'i32, 501,
+    0x004F2'i32, 501,
+    0x004F4'i32, 501,
+    0x004F6'i32, 501,
+    0x004F8'i32, 501,
+    0x004FA'i32, 501,
+    0x004FC'i32, 501,
+    0x004FE'i32, 501,
+    0x00500'i32, 501,
+    0x00502'i32, 501,
+    0x00504'i32, 501,
+    0x00506'i32, 501,
+    0x00508'i32, 501,
+    0x0050A'i32, 501,
+    0x0050C'i32, 501,
+    0x0050E'i32, 501,
+    0x00510'i32, 501,
+    0x00512'i32, 501,
+    0x00514'i32, 501,
+    0x00516'i32, 501,
+    0x00518'i32, 501,
+    0x0051A'i32, 501,
+    0x0051C'i32, 501,
+    0x0051E'i32, 501,
+    0x00520'i32, 501,
+    0x00522'i32, 501,
+    0x00524'i32, 501,
+    0x00526'i32, 501,
+    0x00528'i32, 501,
+    0x0052A'i32, 501,
+    0x0052C'i32, 501,
+    0x0052E'i32, 501,
+    0x010C7'i32, 7764,
+    0x010CD'i32, 7764,
+    0x01E00'i32, 501,
+    0x01E02'i32, 501,
+    0x01E04'i32, 501,
+    0x01E06'i32, 501,
+    0x01E08'i32, 501,
+    0x01E0A'i32, 501,
+    0x01E0C'i32, 501,
+    0x01E0E'i32, 501,
+    0x01E10'i32, 501,
+    0x01E12'i32, 501,
+    0x01E14'i32, 501,
+    0x01E16'i32, 501,
+    0x01E18'i32, 501,
+    0x01E1A'i32, 501,
+    0x01E1C'i32, 501,
+    0x01E1E'i32, 501,
+    0x01E20'i32, 501,
+    0x01E22'i32, 501,
+    0x01E24'i32, 501,
+    0x01E26'i32, 501,
+    0x01E28'i32, 501,
+    0x01E2A'i32, 501,
+    0x01E2C'i32, 501,
+    0x01E2E'i32, 501,
+    0x01E30'i32, 501,
+    0x01E32'i32, 501,
+    0x01E34'i32, 501,
+    0x01E36'i32, 501,
+    0x01E38'i32, 501,
+    0x01E3A'i32, 501,
+    0x01E3C'i32, 501,
+    0x01E3E'i32, 501,
+    0x01E40'i32, 501,
+    0x01E42'i32, 501,
+    0x01E44'i32, 501,
+    0x01E46'i32, 501,
+    0x01E48'i32, 501,
+    0x01E4A'i32, 501,
+    0x01E4C'i32, 501,
+    0x01E4E'i32, 501,
+    0x01E50'i32, 501,
+    0x01E52'i32, 501,
+    0x01E54'i32, 501,
+    0x01E56'i32, 501,
+    0x01E58'i32, 501,
+    0x01E5A'i32, 501,
+    0x01E5C'i32, 501,
+    0x01E5E'i32, 501,
+    0x01E60'i32, 501,
+    0x01E62'i32, 501,
+    0x01E64'i32, 501,
+    0x01E66'i32, 501,
+    0x01E68'i32, 501,
+    0x01E6A'i32, 501,
+    0x01E6C'i32, 501,
+    0x01E6E'i32, 501,
+    0x01E70'i32, 501,
+    0x01E72'i32, 501,
+    0x01E74'i32, 501,
+    0x01E76'i32, 501,
+    0x01E78'i32, 501,
+    0x01E7A'i32, 501,
+    0x01E7C'i32, 501,
+    0x01E7E'i32, 501,
+    0x01E80'i32, 501,
+    0x01E82'i32, 501,
+    0x01E84'i32, 501,
+    0x01E86'i32, 501,
+    0x01E88'i32, 501,
+    0x01E8A'i32, 501,
+    0x01E8C'i32, 501,
+    0x01E8E'i32, 501,
+    0x01E90'i32, 501,
+    0x01E92'i32, 501,
+    0x01E94'i32, 501,
+    0x01E9E'i32, -7115,
+    0x01EA0'i32, 501,
+    0x01EA2'i32, 501,
+    0x01EA4'i32, 501,
+    0x01EA6'i32, 501,
+    0x01EA8'i32, 501,
+    0x01EAA'i32, 501,
+    0x01EAC'i32, 501,
+    0x01EAE'i32, 501,
+    0x01EB0'i32, 501,
+    0x01EB2'i32, 501,
+    0x01EB4'i32, 501,
+    0x01EB6'i32, 501,
+    0x01EB8'i32, 501,
+    0x01EBA'i32, 501,
+    0x01EBC'i32, 501,
+    0x01EBE'i32, 501,
+    0x01EC0'i32, 501,
+    0x01EC2'i32, 501,
+    0x01EC4'i32, 501,
+    0x01EC6'i32, 501,
+    0x01EC8'i32, 501,
+    0x01ECA'i32, 501,
+    0x01ECC'i32, 501,
+    0x01ECE'i32, 501,
+    0x01ED0'i32, 501,
+    0x01ED2'i32, 501,
+    0x01ED4'i32, 501,
+    0x01ED6'i32, 501,
+    0x01ED8'i32, 501,
+    0x01EDA'i32, 501,
+    0x01EDC'i32, 501,
+    0x01EDE'i32, 501,
+    0x01EE0'i32, 501,
+    0x01EE2'i32, 501,
+    0x01EE4'i32, 501,
+    0x01EE6'i32, 501,
+    0x01EE8'i32, 501,
+    0x01EEA'i32, 501,
+    0x01EEC'i32, 501,
+    0x01EEE'i32, 501,
+    0x01EF0'i32, 501,
+    0x01EF2'i32, 501,
+    0x01EF4'i32, 501,
+    0x01EF6'i32, 501,
+    0x01EF8'i32, 501,
+    0x01EFA'i32, 501,
+    0x01EFC'i32, 501,
+    0x01EFE'i32, 501,
+    0x01F59'i32, 492,
+    0x01F5B'i32, 492,
+    0x01F5D'i32, 492,
+    0x01F5F'i32, 492,
+    0x01FBC'i32, 491,
+    0x01FCC'i32, 491,
+    0x01FEC'i32, 493,
+    0x01FFC'i32, 491,
+    0x02126'i32, -7017,
+    0x0212A'i32, -7883,
+    0x0212B'i32, -7762,
+    0x02132'i32, 528,
+    0x02183'i32, 501,
+    0x02C60'i32, 501,
+    0x02C62'i32, -10243,
+    0x02C63'i32, -3314,
+    0x02C64'i32, -10227,
+    0x02C67'i32, 501,
+    0x02C69'i32, 501,
+    0x02C6B'i32, 501,
+    0x02C6D'i32, -10280,
+    0x02C6E'i32, -10249,
+    0x02C6F'i32, -10283,
+    0x02C70'i32, -10282,
+    0x02C72'i32, 501,
+    0x02C75'i32, 501,
+    0x02C80'i32, 501,
+    0x02C82'i32, 501,
+    0x02C84'i32, 501,
+    0x02C86'i32, 501,
+    0x02C88'i32, 501,
+    0x02C8A'i32, 501,
+    0x02C8C'i32, 501,
+    0x02C8E'i32, 501,
+    0x02C90'i32, 501,
+    0x02C92'i32, 501,
+    0x02C94'i32, 501,
+    0x02C96'i32, 501,
+    0x02C98'i32, 501,
+    0x02C9A'i32, 501,
+    0x02C9C'i32, 501,
+    0x02C9E'i32, 501,
+    0x02CA0'i32, 501,
+    0x02CA2'i32, 501,
+    0x02CA4'i32, 501,
+    0x02CA6'i32, 501,
+    0x02CA8'i32, 501,
+    0x02CAA'i32, 501,
+    0x02CAC'i32, 501,
+    0x02CAE'i32, 501,
+    0x02CB0'i32, 501,
+    0x02CB2'i32, 501,
+    0x02CB4'i32, 501,
+    0x02CB6'i32, 501,
+    0x02CB8'i32, 501,
+    0x02CBA'i32, 501,
+    0x02CBC'i32, 501,
+    0x02CBE'i32, 501,
+    0x02CC0'i32, 501,
+    0x02CC2'i32, 501,
+    0x02CC4'i32, 501,
+    0x02CC6'i32, 501,
+    0x02CC8'i32, 501,
+    0x02CCA'i32, 501,
+    0x02CCC'i32, 501,
+    0x02CCE'i32, 501,
+    0x02CD0'i32, 501,
+    0x02CD2'i32, 501,
+    0x02CD4'i32, 501,
+    0x02CD6'i32, 501,
+    0x02CD8'i32, 501,
+    0x02CDA'i32, 501,
+    0x02CDC'i32, 501,
+    0x02CDE'i32, 501,
+    0x02CE0'i32, 501,
+    0x02CE2'i32, 501,
+    0x02CEB'i32, 501,
+    0x02CED'i32, 501,
+    0x02CF2'i32, 501,
+    0x0A640'i32, 501,
+    0x0A642'i32, 501,
+    0x0A644'i32, 501,
+    0x0A646'i32, 501,
+    0x0A648'i32, 501,
+    0x0A64A'i32, 501,
+    0x0A64C'i32, 501,
+    0x0A64E'i32, 501,
+    0x0A650'i32, 501,
+    0x0A652'i32, 501,
+    0x0A654'i32, 501,
+    0x0A656'i32, 501,
+    0x0A658'i32, 501,
+    0x0A65A'i32, 501,
+    0x0A65C'i32, 501,
+    0x0A65E'i32, 501,
+    0x0A660'i32, 501,
+    0x0A662'i32, 501,
+    0x0A664'i32, 501,
+    0x0A666'i32, 501,
+    0x0A668'i32, 501,
+    0x0A66A'i32, 501,
+    0x0A66C'i32, 501,
+    0x0A680'i32, 501,
+    0x0A682'i32, 501,
+    0x0A684'i32, 501,
+    0x0A686'i32, 501,
+    0x0A688'i32, 501,
+    0x0A68A'i32, 501,
+    0x0A68C'i32, 501,
+    0x0A68E'i32, 501,
+    0x0A690'i32, 501,
+    0x0A692'i32, 501,
+    0x0A694'i32, 501,
+    0x0A696'i32, 501,
+    0x0A698'i32, 501,
+    0x0A69A'i32, 501,
+    0x0A722'i32, 501,
+    0x0A724'i32, 501,
+    0x0A726'i32, 501,
+    0x0A728'i32, 501,
+    0x0A72A'i32, 501,
+    0x0A72C'i32, 501,
+    0x0A72E'i32, 501,
+    0x0A732'i32, 501,
+    0x0A734'i32, 501,
+    0x0A736'i32, 501,
+    0x0A738'i32, 501,
+    0x0A73A'i32, 501,
+    0x0A73C'i32, 501,
+    0x0A73E'i32, 501,
+    0x0A740'i32, 501,
+    0x0A742'i32, 501,
+    0x0A744'i32, 501,
+    0x0A746'i32, 501,
+    0x0A748'i32, 501,
+    0x0A74A'i32, 501,
+    0x0A74C'i32, 501,
+    0x0A74E'i32, 501,
+    0x0A750'i32, 501,
+    0x0A752'i32, 501,
+    0x0A754'i32, 501,
+    0x0A756'i32, 501,
+    0x0A758'i32, 501,
+    0x0A75A'i32, 501,
+    0x0A75C'i32, 501,
+    0x0A75E'i32, 501,
+    0x0A760'i32, 501,
+    0x0A762'i32, 501,
+    0x0A764'i32, 501,
+    0x0A766'i32, 501,
+    0x0A768'i32, 501,
+    0x0A76A'i32, 501,
+    0x0A76C'i32, 501,
+    0x0A76E'i32, 501,
+    0x0A779'i32, 501,
+    0x0A77B'i32, 501,
+    0x0A77D'i32, -34832,
+    0x0A77E'i32, 501,
+    0x0A780'i32, 501,
+    0x0A782'i32, 501,
+    0x0A784'i32, 501,
+    0x0A786'i32, 501,
+    0x0A78B'i32, 501,
+    0x0A78D'i32, -41780,
+    0x0A790'i32, 501,
+    0x0A792'i32, 501,
+    0x0A796'i32, 501,
+    0x0A798'i32, 501,
+    0x0A79A'i32, 501,
+    0x0A79C'i32, 501,
+    0x0A79E'i32, 501,
+    0x0A7A0'i32, 501,
+    0x0A7A2'i32, 501,
+    0x0A7A4'i32, 501,
+    0x0A7A6'i32, 501,
+    0x0A7A8'i32, 501,
+    0x0A7AA'i32, -41808,
+    0x0A7AB'i32, -41819,
+    0x0A7AC'i32, -41815,
+    0x0A7AD'i32, -41805,
+    0x0A7AE'i32, -41808,
+    0x0A7B0'i32, -41758,
+    0x0A7B1'i32, -41782,
+    0x0A7B2'i32, -41761,
+    0x0A7B3'i32, 1428,
+    0x0A7B4'i32, 501,
+    0x0A7B6'i32, 501,
+    0x0A7B8'i32, 501,
+    0x0A7BA'i32, 501,
+    0x0A7BC'i32, 501,
+    0x0A7BE'i32, 501,
+    0x0A7C2'i32, 501,
+    0x0A7C4'i32, 452,
+    0x0A7C5'i32, -41807,
+    0x0A7C6'i32, -34884,
   ]
 
   toUpperRanges = [
-    0x00061'i32, 0x0007A, 468,
-    0x000E0, 0x000F6, 468,
-    0x000F8, 0x000FE, 468,
-    0x0023F, 0x00240, 11315,
-    0x00256, 0x00257, 295,
-    0x0028A, 0x0028B, 283,
-    0x0037B, 0x0037D, 630,
-    0x003AD, 0x003AF, 463,
-    0x003B1, 0x003C1, 468,
-    0x003C3, 0x003CB, 468,
-    0x003CD, 0x003CE, 437,
-    0x00430, 0x0044F, 468,
-    0x00450, 0x0045F, 420,
-    0x00561, 0x00586, 452,
-    0x010D0, 0x010FA, 3508,
-    0x010FD, 0x010FF, 3508,
-    0x013F8, 0x013FD, 492,
-    0x01C83, 0x01C84, -5742,
-    0x01F00, 0x01F07, 508,
-    0x01F10, 0x01F15, 508,
-    0x01F20, 0x01F27, 508,
-    0x01F30, 0x01F37, 508,
-    0x01F40, 0x01F45, 508,
-    0x01F60, 0x01F67, 508,
-    0x01F70, 0x01F71, 574,
-    0x01F72, 0x01F75, 586,
-    0x01F76, 0x01F77, 600,
-    0x01F78, 0x01F79, 628,
-    0x01F7A, 0x01F7B, 612,
-    0x01F7C, 0x01F7D, 626,
-    0x01F80, 0x01F87, 508,
-    0x01F90, 0x01F97, 508,
-    0x01FA0, 0x01FA7, 508,
-    0x01FB0, 0x01FB1, 508,
-    0x01FD0, 0x01FD1, 508,
-    0x01FE0, 0x01FE1, 508,
-    0x02C30, 0x02C5E, 452,
-    0x02D00, 0x02D25, -6764,
-    0x0AB70, 0x0ABBF, -38364,
-    0x0FF41, 0x0FF5A, 468,
-    0x10428, 0x1044F, 460,
-    0x104D8, 0x104FB, 460,
-    0x10CC0, 0x10CF2, 436,
-    0x118C0, 0x118DF, 468,
-    0x16E60, 0x16E7F, 468,
-    0x1E922, 0x1E943, 466,
+    0x00061'i32, 0x0007A'i32, 468,
+    0x000E0'i32, 0x000F6'i32, 468,
+    0x000F8'i32, 0x000FE'i32, 468,
+    0x0023F'i32, 0x00240'i32, 11315,
+    0x00256'i32, 0x00257'i32, 295,
+    0x0028A'i32, 0x0028B'i32, 283,
+    0x0037B'i32, 0x0037D'i32, 630,
+    0x003AD'i32, 0x003AF'i32, 463,
+    0x003B1'i32, 0x003C1'i32, 468,
+    0x003C3'i32, 0x003CB'i32, 468,
+    0x003CD'i32, 0x003CE'i32, 437,
+    0x00430'i32, 0x0044F'i32, 468,
+    0x00450'i32, 0x0045F'i32, 420,
+    0x00561'i32, 0x00586'i32, 452,
+    0x010D0'i32, 0x010FA'i32, 3508,
+    0x010FD'i32, 0x010FF'i32, 3508,
+    0x013F8'i32, 0x013FD'i32, 492,
+    0x01C83'i32, 0x01C84'i32, -5742,
+    0x01F00'i32, 0x01F07'i32, 508,
+    0x01F10'i32, 0x01F15'i32, 508,
+    0x01F20'i32, 0x01F27'i32, 508,
+    0x01F30'i32, 0x01F37'i32, 508,
+    0x01F40'i32, 0x01F45'i32, 508,
+    0x01F60'i32, 0x01F67'i32, 508,
+    0x01F70'i32, 0x01F71'i32, 574,
+    0x01F72'i32, 0x01F75'i32, 586,
+    0x01F76'i32, 0x01F77'i32, 600,
+    0x01F78'i32, 0x01F79'i32, 628,
+    0x01F7A'i32, 0x01F7B'i32, 612,
+    0x01F7C'i32, 0x01F7D'i32, 626,
+    0x01F80'i32, 0x01F87'i32, 508,
+    0x01F90'i32, 0x01F97'i32, 508,
+    0x01FA0'i32, 0x01FA7'i32, 508,
+    0x01FB0'i32, 0x01FB1'i32, 508,
+    0x01FD0'i32, 0x01FD1'i32, 508,
+    0x01FE0'i32, 0x01FE1'i32, 508,
+    0x02C30'i32, 0x02C5E'i32, 452,
+    0x02D00'i32, 0x02D25'i32, -6764,
+    0x0AB70'i32, 0x0ABBF'i32, -38364,
+    0x0FF41'i32, 0x0FF5A'i32, 468,
+    0x10428'i32, 0x1044F'i32, 460,
+    0x104D8'i32, 0x104FB'i32, 460,
+    0x10CC0'i32, 0x10CF2'i32, 436,
+    0x118C0'i32, 0x118DF'i32, 468,
+    0x16E60'i32, 0x16E7F'i32, 468,
+    0x1E922'i32, 0x1E943'i32, 466,
   ]
 
   toUpperSinglets = [
     0x000B5'i32, 1243,
-    0x000FF, 621,
-    0x00101, 499,
-    0x00103, 499,
-    0x00105, 499,
-    0x00107, 499,
-    0x00109, 499,
-    0x0010B, 499,
-    0x0010D, 499,
-    0x0010F, 499,
-    0x00111, 499,
-    0x00113, 499,
-    0x00115, 499,
-    0x00117, 499,
-    0x00119, 499,
-    0x0011B, 499,
-    0x0011D, 499,
-    0x0011F, 499,
-    0x00121, 499,
-    0x00123, 499,
-    0x00125, 499,
-    0x00127, 499,
-    0x00129, 499,
-    0x0012B, 499,
-    0x0012D, 499,
-    0x0012F, 499,
-    0x00131, 268,
-    0x00133, 499,
-    0x00135, 499,
-    0x00137, 499,
-    0x0013A, 499,
-    0x0013C, 499,
-    0x0013E, 499,
-    0x00140, 499,
-    0x00142, 499,
-    0x00144, 499,
-    0x00146, 499,
-    0x00148, 499,
-    0x0014B, 499,
-    0x0014D, 499,
-    0x0014F, 499,
-    0x00151, 499,
-    0x00153, 499,
-    0x00155, 499,
-    0x00157, 499,
-    0x00159, 499,
-    0x0015B, 499,
-    0x0015D, 499,
-    0x0015F, 499,
-    0x00161, 499,
-    0x00163, 499,
-    0x00165, 499,
-    0x00167, 499,
-    0x00169, 499,
-    0x0016B, 499,
-    0x0016D, 499,
-    0x0016F, 499,
-    0x00171, 499,
-    0x00173, 499,
-    0x00175, 499,
-    0x00177, 499,
-    0x0017A, 499,
-    0x0017C, 499,
-    0x0017E, 499,
-    0x0017F, 200,
-    0x00180, 695,
-    0x00183, 499,
-    0x00185, 499,
-    0x00188, 499,
-    0x0018C, 499,
-    0x00192, 499,
-    0x00195, 597,
-    0x00199, 499,
-    0x0019A, 663,
-    0x0019E, 630,
-    0x001A1, 499,
-    0x001A3, 499,
-    0x001A5, 499,
-    0x001A8, 499,
-    0x001AD, 499,
-    0x001B0, 499,
-    0x001B4, 499,
-    0x001B6, 499,
-    0x001B9, 499,
-    0x001BD, 499,
-    0x001BF, 556,
-    0x001C5, 499,
-    0x001C6, 498,
-    0x001C8, 499,
-    0x001C9, 498,
-    0x001CB, 499,
-    0x001CC, 498,
-    0x001CE, 499,
-    0x001D0, 499,
-    0x001D2, 499,
-    0x001D4, 499,
-    0x001D6, 499,
-    0x001D8, 499,
-    0x001DA, 499,
-    0x001DC, 499,
-    0x001DD, 421,
-    0x001DF, 499,
-    0x001E1, 499,
-    0x001E3, 499,
-    0x001E5, 499,
-    0x001E7, 499,
-    0x001E9, 499,
-    0x001EB, 499,
-    0x001ED, 499,
-    0x001EF, 499,
-    0x001F2, 499,
-    0x001F3, 498,
-    0x001F5, 499,
-    0x001F9, 499,
-    0x001FB, 499,
-    0x001FD, 499,
-    0x001FF, 499,
-    0x00201, 499,
-    0x00203, 499,
-    0x00205, 499,
-    0x00207, 499,
-    0x00209, 499,
-    0x0020B, 499,
-    0x0020D, 499,
-    0x0020F, 499,
-    0x00211, 499,
-    0x00213, 499,
-    0x00215, 499,
-    0x00217, 499,
-    0x00219, 499,
-    0x0021B, 499,
-    0x0021D, 499,
-    0x0021F, 499,
-    0x00223, 499,
-    0x00225, 499,
-    0x00227, 499,
-    0x00229, 499,
-    0x0022B, 499,
-    0x0022D, 499,
-    0x0022F, 499,
-    0x00231, 499,
-    0x00233, 499,
-    0x0023C, 499,
-    0x00242, 499,
-    0x00247, 499,
-    0x00249, 499,
-    0x0024B, 499,
-    0x0024D, 499,
-    0x0024F, 499,
-    0x00250, 11283,
-    0x00251, 11280,
-    0x00252, 11282,
-    0x00253, 290,
-    0x00254, 294,
-    0x00259, 298,
-    0x0025B, 297,
-    0x0025C, 42819,
-    0x00260, 295,
-    0x00261, 42815,
-    0x00263, 293,
-    0x00265, 42780,
-    0x00266, 42808,
-    0x00268, 291,
-    0x00269, 289,
-    0x0026A, 42808,
-    0x0026B, 11243,
-    0x0026C, 42805,
-    0x0026F, 289,
-    0x00271, 11249,
-    0x00272, 287,
-    0x00275, 286,
-    0x0027D, 11227,
-    0x00280, 282,
-    0x00282, 42807,
-    0x00283, 282,
-    0x00287, 42782,
-    0x00288, 282,
-    0x00289, 431,
-    0x0028C, 429,
-    0x00292, 281,
-    0x0029D, 42761,
-    0x0029E, 42758,
-    0x00371, 499,
-    0x00373, 499,
-    0x00377, 499,
-    0x003AC, 462,
-    0x003C2, 469,
-    0x003CC, 436,
-    0x003D0, 438,
-    0x003D1, 443,
-    0x003D5, 453,
-    0x003D6, 446,
-    0x003D7, 492,
-    0x003D9, 499,
-    0x003DB, 499,
-    0x003DD, 499,
-    0x003DF, 499,
-    0x003E1, 499,
-    0x003E3, 499,
-    0x003E5, 499,
-    0x003E7, 499,
-    0x003E9, 499,
-    0x003EB, 499,
-    0x003ED, 499,
-    0x003EF, 499,
-    0x003F0, 414,
-    0x003F1, 420,
-    0x003F2, 507,
-    0x003F3, 384,
-    0x003F5, 404,
-    0x003F8, 499,
-    0x003FB, 499,
-    0x00461, 499,
-    0x00463, 499,
-    0x00465, 499,
-    0x00467, 499,
-    0x00469, 499,
-    0x0046B, 499,
-    0x0046D, 499,
-    0x0046F, 499,
-    0x00471, 499,
-    0x00473, 499,
-    0x00475, 499,
-    0x00477, 499,
-    0x00479, 499,
-    0x0047B, 499,
-    0x0047D, 499,
-    0x0047F, 499,
-    0x00481, 499,
-    0x0048B, 499,
-    0x0048D, 499,
-    0x0048F, 499,
-    0x00491, 499,
-    0x00493, 499,
-    0x00495, 499,
-    0x00497, 499,
-    0x00499, 499,
-    0x0049B, 499,
-    0x0049D, 499,
-    0x0049F, 499,
-    0x004A1, 499,
-    0x004A3, 499,
-    0x004A5, 499,
-    0x004A7, 499,
-    0x004A9, 499,
-    0x004AB, 499,
-    0x004AD, 499,
-    0x004AF, 499,
-    0x004B1, 499,
-    0x004B3, 499,
-    0x004B5, 499,
-    0x004B7, 499,
-    0x004B9, 499,
-    0x004BB, 499,
-    0x004BD, 499,
-    0x004BF, 499,
-    0x004C2, 499,
-    0x004C4, 499,
-    0x004C6, 499,
-    0x004C8, 499,
-    0x004CA, 499,
-    0x004CC, 499,
-    0x004CE, 499,
-    0x004CF, 485,
-    0x004D1, 499,
-    0x004D3, 499,
-    0x004D5, 499,
-    0x004D7, 499,
-    0x004D9, 499,
-    0x004DB, 499,
-    0x004DD, 499,
-    0x004DF, 499,
-    0x004E1, 499,
-    0x004E3, 499,
-    0x004E5, 499,
-    0x004E7, 499,
-    0x004E9, 499,
-    0x004EB, 499,
-    0x004ED, 499,
-    0x004EF, 499,
-    0x004F1, 499,
-    0x004F3, 499,
-    0x004F5, 499,
-    0x004F7, 499,
-    0x004F9, 499,
-    0x004FB, 499,
-    0x004FD, 499,
-    0x004FF, 499,
-    0x00501, 499,
-    0x00503, 499,
-    0x00505, 499,
-    0x00507, 499,
-    0x00509, 499,
-    0x0050B, 499,
-    0x0050D, 499,
-    0x0050F, 499,
-    0x00511, 499,
-    0x00513, 499,
-    0x00515, 499,
-    0x00517, 499,
-    0x00519, 499,
-    0x0051B, 499,
-    0x0051D, 499,
-    0x0051F, 499,
-    0x00521, 499,
-    0x00523, 499,
-    0x00525, 499,
-    0x00527, 499,
-    0x00529, 499,
-    0x0052B, 499,
-    0x0052D, 499,
-    0x0052F, 499,
-    0x01C80, -5754,
-    0x01C81, -5753,
-    0x01C82, -5744,
-    0x01C85, -5743,
-    0x01C86, -5736,
-    0x01C87, -5681,
-    0x01C88, 35766,
-    0x01D79, 35832,
-    0x01D7D, 4314,
-    0x01D8E, 35884,
-    0x01E01, 499,
-    0x01E03, 499,
-    0x01E05, 499,
-    0x01E07, 499,
-    0x01E09, 499,
-    0x01E0B, 499,
-    0x01E0D, 499,
-    0x01E0F, 499,
-    0x01E11, 499,
-    0x01E13, 499,
-    0x01E15, 499,
-    0x01E17, 499,
-    0x01E19, 499,
-    0x01E1B, 499,
-    0x01E1D, 499,
-    0x01E1F, 499,
-    0x01E21, 499,
-    0x01E23, 499,
-    0x01E25, 499,
-    0x01E27, 499,
-    0x01E29, 499,
-    0x01E2B, 499,
-    0x01E2D, 499,
-    0x01E2F, 499,
-    0x01E31, 499,
-    0x01E33, 499,
-    0x01E35, 499,
-    0x01E37, 499,
-    0x01E39, 499,
-    0x01E3B, 499,
-    0x01E3D, 499,
-    0x01E3F, 499,
-    0x01E41, 499,
-    0x01E43, 499,
-    0x01E45, 499,
-    0x01E47, 499,
-    0x01E49, 499,
-    0x01E4B, 499,
-    0x01E4D, 499,
-    0x01E4F, 499,
-    0x01E51, 499,
-    0x01E53, 499,
-    0x01E55, 499,
-    0x01E57, 499,
-    0x01E59, 499,
-    0x01E5B, 499,
-    0x01E5D, 499,
-    0x01E5F, 499,
-    0x01E61, 499,
-    0x01E63, 499,
-    0x01E65, 499,
-    0x01E67, 499,
-    0x01E69, 499,
-    0x01E6B, 499,
-    0x01E6D, 499,
-    0x01E6F, 499,
-    0x01E71, 499,
-    0x01E73, 499,
-    0x01E75, 499,
-    0x01E77, 499,
-    0x01E79, 499,
-    0x01E7B, 499,
-    0x01E7D, 499,
-    0x01E7F, 499,
-    0x01E81, 499,
-    0x01E83, 499,
-    0x01E85, 499,
-    0x01E87, 499,
-    0x01E89, 499,
-    0x01E8B, 499,
-    0x01E8D, 499,
-    0x01E8F, 499,
-    0x01E91, 499,
-    0x01E93, 499,
-    0x01E95, 499,
-    0x01E9B, 441,
-    0x01EA1, 499,
-    0x01EA3, 499,
-    0x01EA5, 499,
-    0x01EA7, 499,
-    0x01EA9, 499,
-    0x01EAB, 499,
-    0x01EAD, 499,
-    0x01EAF, 499,
-    0x01EB1, 499,
-    0x01EB3, 499,
-    0x01EB5, 499,
-    0x01EB7, 499,
-    0x01EB9, 499,
-    0x01EBB, 499,
-    0x01EBD, 499,
-    0x01EBF, 499,
-    0x01EC1, 499,
-    0x01EC3, 499,
-    0x01EC5, 499,
-    0x01EC7, 499,
-    0x01EC9, 499,
-    0x01ECB, 499,
-    0x01ECD, 499,
-    0x01ECF, 499,
-    0x01ED1, 499,
-    0x01ED3, 499,
-    0x01ED5, 499,
-    0x01ED7, 499,
-    0x01ED9, 499,
-    0x01EDB, 499,
-    0x01EDD, 499,
-    0x01EDF, 499,
-    0x01EE1, 499,
-    0x01EE3, 499,
-    0x01EE5, 499,
-    0x01EE7, 499,
-    0x01EE9, 499,
-    0x01EEB, 499,
-    0x01EED, 499,
-    0x01EEF, 499,
-    0x01EF1, 499,
-    0x01EF3, 499,
-    0x01EF5, 499,
-    0x01EF7, 499,
-    0x01EF9, 499,
-    0x01EFB, 499,
-    0x01EFD, 499,
-    0x01EFF, 499,
-    0x01F51, 508,
-    0x01F53, 508,
-    0x01F55, 508,
-    0x01F57, 508,
-    0x01FB3, 509,
-    0x01FBE, -6705,
-    0x01FC3, 509,
-    0x01FE5, 507,
-    0x01FF3, 509,
-    0x0214E, 472,
-    0x02184, 499,
-    0x02C61, 499,
-    0x02C65, -10295,
-    0x02C66, -10292,
-    0x02C68, 499,
-    0x02C6A, 499,
-    0x02C6C, 499,
-    0x02C73, 499,
-    0x02C76, 499,
-    0x02C81, 499,
-    0x02C83, 499,
-    0x02C85, 499,
-    0x02C87, 499,
-    0x02C89, 499,
-    0x02C8B, 499,
-    0x02C8D, 499,
-    0x02C8F, 499,
-    0x02C91, 499,
-    0x02C93, 499,
-    0x02C95, 499,
-    0x02C97, 499,
-    0x02C99, 499,
-    0x02C9B, 499,
-    0x02C9D, 499,
-    0x02C9F, 499,
-    0x02CA1, 499,
-    0x02CA3, 499,
-    0x02CA5, 499,
-    0x02CA7, 499,
-    0x02CA9, 499,
-    0x02CAB, 499,
-    0x02CAD, 499,
-    0x02CAF, 499,
-    0x02CB1, 499,
-    0x02CB3, 499,
-    0x02CB5, 499,
-    0x02CB7, 499,
-    0x02CB9, 499,
-    0x02CBB, 499,
-    0x02CBD, 499,
-    0x02CBF, 499,
-    0x02CC1, 499,
-    0x02CC3, 499,
-    0x02CC5, 499,
-    0x02CC7, 499,
-    0x02CC9, 499,
-    0x02CCB, 499,
-    0x02CCD, 499,
-    0x02CCF, 499,
-    0x02CD1, 499,
-    0x02CD3, 499,
-    0x02CD5, 499,
-    0x02CD7, 499,
-    0x02CD9, 499,
-    0x02CDB, 499,
-    0x02CDD, 499,
-    0x02CDF, 499,
-    0x02CE1, 499,
-    0x02CE3, 499,
-    0x02CEC, 499,
-    0x02CEE, 499,
-    0x02CF3, 499,
-    0x02D27, -6764,
-    0x02D2D, -6764,
-    0x0A641, 499,
-    0x0A643, 499,
-    0x0A645, 499,
-    0x0A647, 499,
-    0x0A649, 499,
-    0x0A64B, 499,
-    0x0A64D, 499,
-    0x0A64F, 499,
-    0x0A651, 499,
-    0x0A653, 499,
-    0x0A655, 499,
-    0x0A657, 499,
-    0x0A659, 499,
-    0x0A65B, 499,
-    0x0A65D, 499,
-    0x0A65F, 499,
-    0x0A661, 499,
-    0x0A663, 499,
-    0x0A665, 499,
-    0x0A667, 499,
-    0x0A669, 499,
-    0x0A66B, 499,
-    0x0A66D, 499,
-    0x0A681, 499,
-    0x0A683, 499,
-    0x0A685, 499,
-    0x0A687, 499,
-    0x0A689, 499,
-    0x0A68B, 499,
-    0x0A68D, 499,
-    0x0A68F, 499,
-    0x0A691, 499,
-    0x0A693, 499,
-    0x0A695, 499,
-    0x0A697, 499,
-    0x0A699, 499,
-    0x0A69B, 499,
-    0x0A723, 499,
-    0x0A725, 499,
-    0x0A727, 499,
-    0x0A729, 499,
-    0x0A72B, 499,
-    0x0A72D, 499,
-    0x0A72F, 499,
-    0x0A733, 499,
-    0x0A735, 499,
-    0x0A737, 499,
-    0x0A739, 499,
-    0x0A73B, 499,
-    0x0A73D, 499,
-    0x0A73F, 499,
-    0x0A741, 499,
-    0x0A743, 499,
-    0x0A745, 499,
-    0x0A747, 499,
-    0x0A749, 499,
-    0x0A74B, 499,
-    0x0A74D, 499,
-    0x0A74F, 499,
-    0x0A751, 499,
-    0x0A753, 499,
-    0x0A755, 499,
-    0x0A757, 499,
-    0x0A759, 499,
-    0x0A75B, 499,
-    0x0A75D, 499,
-    0x0A75F, 499,
-    0x0A761, 499,
-    0x0A763, 499,
-    0x0A765, 499,
-    0x0A767, 499,
-    0x0A769, 499,
-    0x0A76B, 499,
-    0x0A76D, 499,
-    0x0A76F, 499,
-    0x0A77A, 499,
-    0x0A77C, 499,
-    0x0A77F, 499,
-    0x0A781, 499,
-    0x0A783, 499,
-    0x0A785, 499,
-    0x0A787, 499,
-    0x0A78C, 499,
-    0x0A791, 499,
-    0x0A793, 499,
-    0x0A794, 548,
-    0x0A797, 499,
-    0x0A799, 499,
-    0x0A79B, 499,
-    0x0A79D, 499,
-    0x0A79F, 499,
-    0x0A7A1, 499,
-    0x0A7A3, 499,
-    0x0A7A5, 499,
-    0x0A7A7, 499,
-    0x0A7A9, 499,
-    0x0A7B5, 499,
-    0x0A7B7, 499,
-    0x0A7B9, 499,
-    0x0A7BB, 499,
-    0x0A7BD, 499,
-    0x0A7BF, 499,
-    0x0A7C3, 499,
-    0x0AB53, -428,
+    0x000FF'i32, 621,
+    0x00101'i32, 499,
+    0x00103'i32, 499,
+    0x00105'i32, 499,
+    0x00107'i32, 499,
+    0x00109'i32, 499,
+    0x0010B'i32, 499,
+    0x0010D'i32, 499,
+    0x0010F'i32, 499,
+    0x00111'i32, 499,
+    0x00113'i32, 499,
+    0x00115'i32, 499,
+    0x00117'i32, 499,
+    0x00119'i32, 499,
+    0x0011B'i32, 499,
+    0x0011D'i32, 499,
+    0x0011F'i32, 499,
+    0x00121'i32, 499,
+    0x00123'i32, 499,
+    0x00125'i32, 499,
+    0x00127'i32, 499,
+    0x00129'i32, 499,
+    0x0012B'i32, 499,
+    0x0012D'i32, 499,
+    0x0012F'i32, 499,
+    0x00131'i32, 268,
+    0x00133'i32, 499,
+    0x00135'i32, 499,
+    0x00137'i32, 499,
+    0x0013A'i32, 499,
+    0x0013C'i32, 499,
+    0x0013E'i32, 499,
+    0x00140'i32, 499,
+    0x00142'i32, 499,
+    0x00144'i32, 499,
+    0x00146'i32, 499,
+    0x00148'i32, 499,
+    0x0014B'i32, 499,
+    0x0014D'i32, 499,
+    0x0014F'i32, 499,
+    0x00151'i32, 499,
+    0x00153'i32, 499,
+    0x00155'i32, 499,
+    0x00157'i32, 499,
+    0x00159'i32, 499,
+    0x0015B'i32, 499,
+    0x0015D'i32, 499,
+    0x0015F'i32, 499,
+    0x00161'i32, 499,
+    0x00163'i32, 499,
+    0x00165'i32, 499,
+    0x00167'i32, 499,
+    0x00169'i32, 499,
+    0x0016B'i32, 499,
+    0x0016D'i32, 499,
+    0x0016F'i32, 499,
+    0x00171'i32, 499,
+    0x00173'i32, 499,
+    0x00175'i32, 499,
+    0x00177'i32, 499,
+    0x0017A'i32, 499,
+    0x0017C'i32, 499,
+    0x0017E'i32, 499,
+    0x0017F'i32, 200,
+    0x00180'i32, 695,
+    0x00183'i32, 499,
+    0x00185'i32, 499,
+    0x00188'i32, 499,
+    0x0018C'i32, 499,
+    0x00192'i32, 499,
+    0x00195'i32, 597,
+    0x00199'i32, 499,
+    0x0019A'i32, 663,
+    0x0019E'i32, 630,
+    0x001A1'i32, 499,
+    0x001A3'i32, 499,
+    0x001A5'i32, 499,
+    0x001A8'i32, 499,
+    0x001AD'i32, 499,
+    0x001B0'i32, 499,
+    0x001B4'i32, 499,
+    0x001B6'i32, 499,
+    0x001B9'i32, 499,
+    0x001BD'i32, 499,
+    0x001BF'i32, 556,
+    0x001C5'i32, 499,
+    0x001C6'i32, 498,
+    0x001C8'i32, 499,
+    0x001C9'i32, 498,
+    0x001CB'i32, 499,
+    0x001CC'i32, 498,
+    0x001CE'i32, 499,
+    0x001D0'i32, 499,
+    0x001D2'i32, 499,
+    0x001D4'i32, 499,
+    0x001D6'i32, 499,
+    0x001D8'i32, 499,
+    0x001DA'i32, 499,
+    0x001DC'i32, 499,
+    0x001DD'i32, 421,
+    0x001DF'i32, 499,
+    0x001E1'i32, 499,
+    0x001E3'i32, 499,
+    0x001E5'i32, 499,
+    0x001E7'i32, 499,
+    0x001E9'i32, 499,
+    0x001EB'i32, 499,
+    0x001ED'i32, 499,
+    0x001EF'i32, 499,
+    0x001F2'i32, 499,
+    0x001F3'i32, 498,
+    0x001F5'i32, 499,
+    0x001F9'i32, 499,
+    0x001FB'i32, 499,
+    0x001FD'i32, 499,
+    0x001FF'i32, 499,
+    0x00201'i32, 499,
+    0x00203'i32, 499,
+    0x00205'i32, 499,
+    0x00207'i32, 499,
+    0x00209'i32, 499,
+    0x0020B'i32, 499,
+    0x0020D'i32, 499,
+    0x0020F'i32, 499,
+    0x00211'i32, 499,
+    0x00213'i32, 499,
+    0x00215'i32, 499,
+    0x00217'i32, 499,
+    0x00219'i32, 499,
+    0x0021B'i32, 499,
+    0x0021D'i32, 499,
+    0x0021F'i32, 499,
+    0x00223'i32, 499,
+    0x00225'i32, 499,
+    0x00227'i32, 499,
+    0x00229'i32, 499,
+    0x0022B'i32, 499,
+    0x0022D'i32, 499,
+    0x0022F'i32, 499,
+    0x00231'i32, 499,
+    0x00233'i32, 499,
+    0x0023C'i32, 499,
+    0x00242'i32, 499,
+    0x00247'i32, 499,
+    0x00249'i32, 499,
+    0x0024B'i32, 499,
+    0x0024D'i32, 499,
+    0x0024F'i32, 499,
+    0x00250'i32, 11283,
+    0x00251'i32, 11280,
+    0x00252'i32, 11282,
+    0x00253'i32, 290,
+    0x00254'i32, 294,
+    0x00259'i32, 298,
+    0x0025B'i32, 297,
+    0x0025C'i32, 42819,
+    0x00260'i32, 295,
+    0x00261'i32, 42815,
+    0x00263'i32, 293,
+    0x00265'i32, 42780,
+    0x00266'i32, 42808,
+    0x00268'i32, 291,
+    0x00269'i32, 289,
+    0x0026A'i32, 42808,
+    0x0026B'i32, 11243,
+    0x0026C'i32, 42805,
+    0x0026F'i32, 289,
+    0x00271'i32, 11249,
+    0x00272'i32, 287,
+    0x00275'i32, 286,
+    0x0027D'i32, 11227,
+    0x00280'i32, 282,
+    0x00282'i32, 42807,
+    0x00283'i32, 282,
+    0x00287'i32, 42782,
+    0x00288'i32, 282,
+    0x00289'i32, 431,
+    0x0028C'i32, 429,
+    0x00292'i32, 281,
+    0x0029D'i32, 42761,
+    0x0029E'i32, 42758,
+    0x00371'i32, 499,
+    0x00373'i32, 499,
+    0x00377'i32, 499,
+    0x003AC'i32, 462,
+    0x003C2'i32, 469,
+    0x003CC'i32, 436,
+    0x003D0'i32, 438,
+    0x003D1'i32, 443,
+    0x003D5'i32, 453,
+    0x003D6'i32, 446,
+    0x003D7'i32, 492,
+    0x003D9'i32, 499,
+    0x003DB'i32, 499,
+    0x003DD'i32, 499,
+    0x003DF'i32, 499,
+    0x003E1'i32, 499,
+    0x003E3'i32, 499,
+    0x003E5'i32, 499,
+    0x003E7'i32, 499,
+    0x003E9'i32, 499,
+    0x003EB'i32, 499,
+    0x003ED'i32, 499,
+    0x003EF'i32, 499,
+    0x003F0'i32, 414,
+    0x003F1'i32, 420,
+    0x003F2'i32, 507,
+    0x003F3'i32, 384,
+    0x003F5'i32, 404,
+    0x003F8'i32, 499,
+    0x003FB'i32, 499,
+    0x00461'i32, 499,
+    0x00463'i32, 499,
+    0x00465'i32, 499,
+    0x00467'i32, 499,
+    0x00469'i32, 499,
+    0x0046B'i32, 499,
+    0x0046D'i32, 499,
+    0x0046F'i32, 499,
+    0x00471'i32, 499,
+    0x00473'i32, 499,
+    0x00475'i32, 499,
+    0x00477'i32, 499,
+    0x00479'i32, 499,
+    0x0047B'i32, 499,
+    0x0047D'i32, 499,
+    0x0047F'i32, 499,
+    0x00481'i32, 499,
+    0x0048B'i32, 499,
+    0x0048D'i32, 499,
+    0x0048F'i32, 499,
+    0x00491'i32, 499,
+    0x00493'i32, 499,
+    0x00495'i32, 499,
+    0x00497'i32, 499,
+    0x00499'i32, 499,
+    0x0049B'i32, 499,
+    0x0049D'i32, 499,
+    0x0049F'i32, 499,
+    0x004A1'i32, 499,
+    0x004A3'i32, 499,
+    0x004A5'i32, 499,
+    0x004A7'i32, 499,
+    0x004A9'i32, 499,
+    0x004AB'i32, 499,
+    0x004AD'i32, 499,
+    0x004AF'i32, 499,
+    0x004B1'i32, 499,
+    0x004B3'i32, 499,
+    0x004B5'i32, 499,
+    0x004B7'i32, 499,
+    0x004B9'i32, 499,
+    0x004BB'i32, 499,
+    0x004BD'i32, 499,
+    0x004BF'i32, 499,
+    0x004C2'i32, 499,
+    0x004C4'i32, 499,
+    0x004C6'i32, 499,
+    0x004C8'i32, 499,
+    0x004CA'i32, 499,
+    0x004CC'i32, 499,
+    0x004CE'i32, 499,
+    0x004CF'i32, 485,
+    0x004D1'i32, 499,
+    0x004D3'i32, 499,
+    0x004D5'i32, 499,
+    0x004D7'i32, 499,
+    0x004D9'i32, 499,
+    0x004DB'i32, 499,
+    0x004DD'i32, 499,
+    0x004DF'i32, 499,
+    0x004E1'i32, 499,
+    0x004E3'i32, 499,
+    0x004E5'i32, 499,
+    0x004E7'i32, 499,
+    0x004E9'i32, 499,
+    0x004EB'i32, 499,
+    0x004ED'i32, 499,
+    0x004EF'i32, 499,
+    0x004F1'i32, 499,
+    0x004F3'i32, 499,
+    0x004F5'i32, 499,
+    0x004F7'i32, 499,
+    0x004F9'i32, 499,
+    0x004FB'i32, 499,
+    0x004FD'i32, 499,
+    0x004FF'i32, 499,
+    0x00501'i32, 499,
+    0x00503'i32, 499,
+    0x00505'i32, 499,
+    0x00507'i32, 499,
+    0x00509'i32, 499,
+    0x0050B'i32, 499,
+    0x0050D'i32, 499,
+    0x0050F'i32, 499,
+    0x00511'i32, 499,
+    0x00513'i32, 499,
+    0x00515'i32, 499,
+    0x00517'i32, 499,
+    0x00519'i32, 499,
+    0x0051B'i32, 499,
+    0x0051D'i32, 499,
+    0x0051F'i32, 499,
+    0x00521'i32, 499,
+    0x00523'i32, 499,
+    0x00525'i32, 499,
+    0x00527'i32, 499,
+    0x00529'i32, 499,
+    0x0052B'i32, 499,
+    0x0052D'i32, 499,
+    0x0052F'i32, 499,
+    0x01C80'i32, -5754,
+    0x01C81'i32, -5753,
+    0x01C82'i32, -5744,
+    0x01C85'i32, -5743,
+    0x01C86'i32, -5736,
+    0x01C87'i32, -5681,
+    0x01C88'i32, 35766,
+    0x01D79'i32, 35832,
+    0x01D7D'i32, 4314,
+    0x01D8E'i32, 35884,
+    0x01E01'i32, 499,
+    0x01E03'i32, 499,
+    0x01E05'i32, 499,
+    0x01E07'i32, 499,
+    0x01E09'i32, 499,
+    0x01E0B'i32, 499,
+    0x01E0D'i32, 499,
+    0x01E0F'i32, 499,
+    0x01E11'i32, 499,
+    0x01E13'i32, 499,
+    0x01E15'i32, 499,
+    0x01E17'i32, 499,
+    0x01E19'i32, 499,
+    0x01E1B'i32, 499,
+    0x01E1D'i32, 499,
+    0x01E1F'i32, 499,
+    0x01E21'i32, 499,
+    0x01E23'i32, 499,
+    0x01E25'i32, 499,
+    0x01E27'i32, 499,
+    0x01E29'i32, 499,
+    0x01E2B'i32, 499,
+    0x01E2D'i32, 499,
+    0x01E2F'i32, 499,
+    0x01E31'i32, 499,
+    0x01E33'i32, 499,
+    0x01E35'i32, 499,
+    0x01E37'i32, 499,
+    0x01E39'i32, 499,
+    0x01E3B'i32, 499,
+    0x01E3D'i32, 499,
+    0x01E3F'i32, 499,
+    0x01E41'i32, 499,
+    0x01E43'i32, 499,
+    0x01E45'i32, 499,
+    0x01E47'i32, 499,
+    0x01E49'i32, 499,
+    0x01E4B'i32, 499,
+    0x01E4D'i32, 499,
+    0x01E4F'i32, 499,
+    0x01E51'i32, 499,
+    0x01E53'i32, 499,
+    0x01E55'i32, 499,
+    0x01E57'i32, 499,
+    0x01E59'i32, 499,
+    0x01E5B'i32, 499,
+    0x01E5D'i32, 499,
+    0x01E5F'i32, 499,
+    0x01E61'i32, 499,
+    0x01E63'i32, 499,
+    0x01E65'i32, 499,
+    0x01E67'i32, 499,
+    0x01E69'i32, 499,
+    0x01E6B'i32, 499,
+    0x01E6D'i32, 499,
+    0x01E6F'i32, 499,
+    0x01E71'i32, 499,
+    0x01E73'i32, 499,
+    0x01E75'i32, 499,
+    0x01E77'i32, 499,
+    0x01E79'i32, 499,
+    0x01E7B'i32, 499,
+    0x01E7D'i32, 499,
+    0x01E7F'i32, 499,
+    0x01E81'i32, 499,
+    0x01E83'i32, 499,
+    0x01E85'i32, 499,
+    0x01E87'i32, 499,
+    0x01E89'i32, 499,
+    0x01E8B'i32, 499,
+    0x01E8D'i32, 499,
+    0x01E8F'i32, 499,
+    0x01E91'i32, 499,
+    0x01E93'i32, 499,
+    0x01E95'i32, 499,
+    0x01E9B'i32, 441,
+    0x01EA1'i32, 499,
+    0x01EA3'i32, 499,
+    0x01EA5'i32, 499,
+    0x01EA7'i32, 499,
+    0x01EA9'i32, 499,
+    0x01EAB'i32, 499,
+    0x01EAD'i32, 499,
+    0x01EAF'i32, 499,
+    0x01EB1'i32, 499,
+    0x01EB3'i32, 499,
+    0x01EB5'i32, 499,
+    0x01EB7'i32, 499,
+    0x01EB9'i32, 499,
+    0x01EBB'i32, 499,
+    0x01EBD'i32, 499,
+    0x01EBF'i32, 499,
+    0x01EC1'i32, 499,
+    0x01EC3'i32, 499,
+    0x01EC5'i32, 499,
+    0x01EC7'i32, 499,
+    0x01EC9'i32, 499,
+    0x01ECB'i32, 499,
+    0x01ECD'i32, 499,
+    0x01ECF'i32, 499,
+    0x01ED1'i32, 499,
+    0x01ED3'i32, 499,
+    0x01ED5'i32, 499,
+    0x01ED7'i32, 499,
+    0x01ED9'i32, 499,
+    0x01EDB'i32, 499,
+    0x01EDD'i32, 499,
+    0x01EDF'i32, 499,
+    0x01EE1'i32, 499,
+    0x01EE3'i32, 499,
+    0x01EE5'i32, 499,
+    0x01EE7'i32, 499,
+    0x01EE9'i32, 499,
+    0x01EEB'i32, 499,
+    0x01EED'i32, 499,
+    0x01EEF'i32, 499,
+    0x01EF1'i32, 499,
+    0x01EF3'i32, 499,
+    0x01EF5'i32, 499,
+    0x01EF7'i32, 499,
+    0x01EF9'i32, 499,
+    0x01EFB'i32, 499,
+    0x01EFD'i32, 499,
+    0x01EFF'i32, 499,
+    0x01F51'i32, 508,
+    0x01F53'i32, 508,
+    0x01F55'i32, 508,
+    0x01F57'i32, 508,
+    0x01FB3'i32, 509,
+    0x01FBE'i32, -6705,
+    0x01FC3'i32, 509,
+    0x01FE5'i32, 507,
+    0x01FF3'i32, 509,
+    0x0214E'i32, 472,
+    0x02184'i32, 499,
+    0x02C61'i32, 499,
+    0x02C65'i32, -10295,
+    0x02C66'i32, -10292,
+    0x02C68'i32, 499,
+    0x02C6A'i32, 499,
+    0x02C6C'i32, 499,
+    0x02C73'i32, 499,
+    0x02C76'i32, 499,
+    0x02C81'i32, 499,
+    0x02C83'i32, 499,
+    0x02C85'i32, 499,
+    0x02C87'i32, 499,
+    0x02C89'i32, 499,
+    0x02C8B'i32, 499,
+    0x02C8D'i32, 499,
+    0x02C8F'i32, 499,
+    0x02C91'i32, 499,
+    0x02C93'i32, 499,
+    0x02C95'i32, 499,
+    0x02C97'i32, 499,
+    0x02C99'i32, 499,
+    0x02C9B'i32, 499,
+    0x02C9D'i32, 499,
+    0x02C9F'i32, 499,
+    0x02CA1'i32, 499,
+    0x02CA3'i32, 499,
+    0x02CA5'i32, 499,
+    0x02CA7'i32, 499,
+    0x02CA9'i32, 499,
+    0x02CAB'i32, 499,
+    0x02CAD'i32, 499,
+    0x02CAF'i32, 499,
+    0x02CB1'i32, 499,
+    0x02CB3'i32, 499,
+    0x02CB5'i32, 499,
+    0x02CB7'i32, 499,
+    0x02CB9'i32, 499,
+    0x02CBB'i32, 499,
+    0x02CBD'i32, 499,
+    0x02CBF'i32, 499,
+    0x02CC1'i32, 499,
+    0x02CC3'i32, 499,
+    0x02CC5'i32, 499,
+    0x02CC7'i32, 499,
+    0x02CC9'i32, 499,
+    0x02CCB'i32, 499,
+    0x02CCD'i32, 499,
+    0x02CCF'i32, 499,
+    0x02CD1'i32, 499,
+    0x02CD3'i32, 499,
+    0x02CD5'i32, 499,
+    0x02CD7'i32, 499,
+    0x02CD9'i32, 499,
+    0x02CDB'i32, 499,
+    0x02CDD'i32, 499,
+    0x02CDF'i32, 499,
+    0x02CE1'i32, 499,
+    0x02CE3'i32, 499,
+    0x02CEC'i32, 499,
+    0x02CEE'i32, 499,
+    0x02CF3'i32, 499,
+    0x02D27'i32, -6764,
+    0x02D2D'i32, -6764,
+    0x0A641'i32, 499,
+    0x0A643'i32, 499,
+    0x0A645'i32, 499,
+    0x0A647'i32, 499,
+    0x0A649'i32, 499,
+    0x0A64B'i32, 499,
+    0x0A64D'i32, 499,
+    0x0A64F'i32, 499,
+    0x0A651'i32, 499,
+    0x0A653'i32, 499,
+    0x0A655'i32, 499,
+    0x0A657'i32, 499,
+    0x0A659'i32, 499,
+    0x0A65B'i32, 499,
+    0x0A65D'i32, 499,
+    0x0A65F'i32, 499,
+    0x0A661'i32, 499,
+    0x0A663'i32, 499,
+    0x0A665'i32, 499,
+    0x0A667'i32, 499,
+    0x0A669'i32, 499,
+    0x0A66B'i32, 499,
+    0x0A66D'i32, 499,
+    0x0A681'i32, 499,
+    0x0A683'i32, 499,
+    0x0A685'i32, 499,
+    0x0A687'i32, 499,
+    0x0A689'i32, 499,
+    0x0A68B'i32, 499,
+    0x0A68D'i32, 499,
+    0x0A68F'i32, 499,
+    0x0A691'i32, 499,
+    0x0A693'i32, 499,
+    0x0A695'i32, 499,
+    0x0A697'i32, 499,
+    0x0A699'i32, 499,
+    0x0A69B'i32, 499,
+    0x0A723'i32, 499,
+    0x0A725'i32, 499,
+    0x0A727'i32, 499,
+    0x0A729'i32, 499,
+    0x0A72B'i32, 499,
+    0x0A72D'i32, 499,
+    0x0A72F'i32, 499,
+    0x0A733'i32, 499,
+    0x0A735'i32, 499,
+    0x0A737'i32, 499,
+    0x0A739'i32, 499,
+    0x0A73B'i32, 499,
+    0x0A73D'i32, 499,
+    0x0A73F'i32, 499,
+    0x0A741'i32, 499,
+    0x0A743'i32, 499,
+    0x0A745'i32, 499,
+    0x0A747'i32, 499,
+    0x0A749'i32, 499,
+    0x0A74B'i32, 499,
+    0x0A74D'i32, 499,
+    0x0A74F'i32, 499,
+    0x0A751'i32, 499,
+    0x0A753'i32, 499,
+    0x0A755'i32, 499,
+    0x0A757'i32, 499,
+    0x0A759'i32, 499,
+    0x0A75B'i32, 499,
+    0x0A75D'i32, 499,
+    0x0A75F'i32, 499,
+    0x0A761'i32, 499,
+    0x0A763'i32, 499,
+    0x0A765'i32, 499,
+    0x0A767'i32, 499,
+    0x0A769'i32, 499,
+    0x0A76B'i32, 499,
+    0x0A76D'i32, 499,
+    0x0A76F'i32, 499,
+    0x0A77A'i32, 499,
+    0x0A77C'i32, 499,
+    0x0A77F'i32, 499,
+    0x0A781'i32, 499,
+    0x0A783'i32, 499,
+    0x0A785'i32, 499,
+    0x0A787'i32, 499,
+    0x0A78C'i32, 499,
+    0x0A791'i32, 499,
+    0x0A793'i32, 499,
+    0x0A794'i32, 548,
+    0x0A797'i32, 499,
+    0x0A799'i32, 499,
+    0x0A79B'i32, 499,
+    0x0A79D'i32, 499,
+    0x0A79F'i32, 499,
+    0x0A7A1'i32, 499,
+    0x0A7A3'i32, 499,
+    0x0A7A5'i32, 499,
+    0x0A7A7'i32, 499,
+    0x0A7A9'i32, 499,
+    0x0A7B5'i32, 499,
+    0x0A7B7'i32, 499,
+    0x0A7B9'i32, 499,
+    0x0A7BB'i32, 499,
+    0x0A7BD'i32, 499,
+    0x0A7BF'i32, 499,
+    0x0A7C3'i32, 499,
+    0x0AB53'i32, -428,
   ]
 
   toTitleSinglets = [
     0x001C4'i32, 501,
-    0x001C6, 499,
-    0x001C7, 501,
-    0x001C9, 499,
-    0x001CA, 501,
-    0x001CC, 499,
-    0x001F1, 501,
-    0x001F3, 499,
+    0x001C6'i32, 499,
+    0x001C7'i32, 501,
+    0x001C9'i32, 499,
+    0x001CA'i32, 501,
+    0x001CC'i32, 499,
+    0x001F1'i32, 501,
+    0x001F3'i32, 499,
   ]
 
   alphaRanges = [
-    0x00041'i32, 0x0005A,
-    0x00061, 0x0007A,
-    0x000C0, 0x000D6,
-    0x000D8, 0x000F6,
-    0x000F8, 0x002C1,
-    0x002C6, 0x002D1,
-    0x002E0, 0x002E4,
-    0x00370, 0x00374,
-    0x00376, 0x00377,
-    0x0037A, 0x0037D,
-    0x00388, 0x0038A,
-    0x0038E, 0x003A1,
-    0x003A3, 0x003F5,
-    0x003F7, 0x00481,
-    0x0048A, 0x0052F,
-    0x00531, 0x00556,
-    0x00560, 0x00588,
-    0x005D0, 0x005EA,
-    0x005EF, 0x005F2,
-    0x00620, 0x0064A,
-    0x0066E, 0x0066F,
-    0x00671, 0x006D3,
-    0x006E5, 0x006E6,
-    0x006EE, 0x006EF,
-    0x006FA, 0x006FC,
-    0x00712, 0x0072F,
-    0x0074D, 0x007A5,
-    0x007CA, 0x007EA,
-    0x007F4, 0x007F5,
-    0x00800, 0x00815,
-    0x00840, 0x00858,
-    0x00860, 0x0086A,
-    0x008A0, 0x008B4,
-    0x008B6, 0x008BD,
-    0x00904, 0x00939,
-    0x00958, 0x00961,
-    0x00971, 0x00980,
-    0x00985, 0x0098C,
-    0x0098F, 0x00990,
-    0x00993, 0x009A8,
-    0x009AA, 0x009B0,
-    0x009B6, 0x009B9,
-    0x009DC, 0x009DD,
-    0x009DF, 0x009E1,
-    0x009F0, 0x009F1,
-    0x00A05, 0x00A0A,
-    0x00A0F, 0x00A10,
-    0x00A13, 0x00A28,
-    0x00A2A, 0x00A30,
-    0x00A32, 0x00A33,
-    0x00A35, 0x00A36,
-    0x00A38, 0x00A39,
-    0x00A59, 0x00A5C,
-    0x00A72, 0x00A74,
-    0x00A85, 0x00A8D,
-    0x00A8F, 0x00A91,
-    0x00A93, 0x00AA8,
-    0x00AAA, 0x00AB0,
-    0x00AB2, 0x00AB3,
-    0x00AB5, 0x00AB9,
-    0x00AE0, 0x00AE1,
-    0x00B05, 0x00B0C,
-    0x00B0F, 0x00B10,
-    0x00B13, 0x00B28,
-    0x00B2A, 0x00B30,
-    0x00B32, 0x00B33,
-    0x00B35, 0x00B39,
-    0x00B5C, 0x00B5D,
-    0x00B5F, 0x00B61,
-    0x00B85, 0x00B8A,
-    0x00B8E, 0x00B90,
-    0x00B92, 0x00B95,
-    0x00B99, 0x00B9A,
-    0x00B9E, 0x00B9F,
-    0x00BA3, 0x00BA4,
-    0x00BA8, 0x00BAA,
-    0x00BAE, 0x00BB9,
-    0x00C05, 0x00C0C,
-    0x00C0E, 0x00C10,
-    0x00C12, 0x00C28,
-    0x00C2A, 0x00C39,
-    0x00C58, 0x00C5A,
-    0x00C60, 0x00C61,
-    0x00C85, 0x00C8C,
-    0x00C8E, 0x00C90,
-    0x00C92, 0x00CA8,
-    0x00CAA, 0x00CB3,
-    0x00CB5, 0x00CB9,
-    0x00CE0, 0x00CE1,
-    0x00CF1, 0x00CF2,
-    0x00D05, 0x00D0C,
-    0x00D0E, 0x00D10,
-    0x00D12, 0x00D3A,
-    0x00D54, 0x00D56,
-    0x00D5F, 0x00D61,
-    0x00D7A, 0x00D7F,
-    0x00D85, 0x00D96,
-    0x00D9A, 0x00DB1,
-    0x00DB3, 0x00DBB,
-    0x00DC0, 0x00DC6,
-    0x00E01, 0x00E30,
-    0x00E32, 0x00E33,
-    0x00E40, 0x00E46,
-    0x00E81, 0x00E82,
-    0x00E86, 0x00E8A,
-    0x00E8C, 0x00EA3,
-    0x00EA7, 0x00EB0,
-    0x00EB2, 0x00EB3,
-    0x00EC0, 0x00EC4,
-    0x00EDC, 0x00EDF,
-    0x00F40, 0x00F47,
-    0x00F49, 0x00F6C,
-    0x00F88, 0x00F8C,
-    0x01000, 0x0102A,
-    0x01050, 0x01055,
-    0x0105A, 0x0105D,
-    0x01065, 0x01066,
-    0x0106E, 0x01070,
-    0x01075, 0x01081,
-    0x010A0, 0x010C5,
-    0x010D0, 0x010FA,
-    0x010FC, 0x01248,
-    0x0124A, 0x0124D,
-    0x01250, 0x01256,
-    0x0125A, 0x0125D,
-    0x01260, 0x01288,
-    0x0128A, 0x0128D,
-    0x01290, 0x012B0,
-    0x012B2, 0x012B5,
-    0x012B8, 0x012BE,
-    0x012C2, 0x012C5,
-    0x012C8, 0x012D6,
-    0x012D8, 0x01310,
-    0x01312, 0x01315,
-    0x01318, 0x0135A,
-    0x01380, 0x0138F,
-    0x013A0, 0x013F5,
-    0x013F8, 0x013FD,
-    0x01401, 0x0166C,
-    0x0166F, 0x0167F,
-    0x01681, 0x0169A,
-    0x016A0, 0x016EA,
-    0x016F1, 0x016F8,
-    0x01700, 0x0170C,
-    0x0170E, 0x01711,
-    0x01720, 0x01731,
-    0x01740, 0x01751,
-    0x01760, 0x0176C,
-    0x0176E, 0x01770,
-    0x01780, 0x017B3,
-    0x01820, 0x01878,
-    0x01880, 0x01884,
-    0x01887, 0x018A8,
-    0x018B0, 0x018F5,
-    0x01900, 0x0191E,
-    0x01950, 0x0196D,
-    0x01970, 0x01974,
-    0x01980, 0x019AB,
-    0x019B0, 0x019C9,
-    0x01A00, 0x01A16,
-    0x01A20, 0x01A54,
-    0x01B05, 0x01B33,
-    0x01B45, 0x01B4B,
-    0x01B83, 0x01BA0,
-    0x01BAE, 0x01BAF,
-    0x01BBA, 0x01BE5,
-    0x01C00, 0x01C23,
-    0x01C4D, 0x01C4F,
-    0x01C5A, 0x01C7D,
-    0x01C80, 0x01C88,
-    0x01C90, 0x01CBA,
-    0x01CBD, 0x01CBF,
-    0x01CE9, 0x01CEC,
-    0x01CEE, 0x01CF3,
-    0x01CF5, 0x01CF6,
-    0x01D00, 0x01DBF,
-    0x01E00, 0x01F15,
-    0x01F18, 0x01F1D,
-    0x01F20, 0x01F45,
-    0x01F48, 0x01F4D,
-    0x01F50, 0x01F57,
-    0x01F5F, 0x01F7D,
-    0x01F80, 0x01FB4,
-    0x01FB6, 0x01FBC,
-    0x01FC2, 0x01FC4,
-    0x01FC6, 0x01FCC,
-    0x01FD0, 0x01FD3,
-    0x01FD6, 0x01FDB,
-    0x01FE0, 0x01FEC,
-    0x01FF2, 0x01FF4,
-    0x01FF6, 0x01FFC,
-    0x02090, 0x0209C,
-    0x0210A, 0x02113,
-    0x02119, 0x0211D,
-    0x0212A, 0x0212D,
-    0x0212F, 0x02139,
-    0x0213C, 0x0213F,
-    0x02145, 0x02149,
-    0x02183, 0x02184,
-    0x02C00, 0x02C2E,
-    0x02C30, 0x02C5E,
-    0x02C60, 0x02CE4,
-    0x02CEB, 0x02CEE,
-    0x02CF2, 0x02CF3,
-    0x02D00, 0x02D25,
-    0x02D30, 0x02D67,
-    0x02D80, 0x02D96,
-    0x02DA0, 0x02DA6,
-    0x02DA8, 0x02DAE,
-    0x02DB0, 0x02DB6,
-    0x02DB8, 0x02DBE,
-    0x02DC0, 0x02DC6,
-    0x02DC8, 0x02DCE,
-    0x02DD0, 0x02DD6,
-    0x02DD8, 0x02DDE,
-    0x03005, 0x03006,
-    0x03031, 0x03035,
-    0x0303B, 0x0303C,
-    0x03041, 0x03096,
-    0x0309D, 0x0309F,
-    0x030A1, 0x030FA,
-    0x030FC, 0x030FF,
-    0x03105, 0x0312F,
-    0x03131, 0x0318E,
-    0x031A0, 0x031BA,
-    0x031F0, 0x031FF,
-    0x0A000, 0x0A48C,
-    0x0A4D0, 0x0A4FD,
-    0x0A500, 0x0A60C,
-    0x0A610, 0x0A61F,
-    0x0A62A, 0x0A62B,
-    0x0A640, 0x0A66E,
-    0x0A67F, 0x0A69D,
-    0x0A6A0, 0x0A6E5,
-    0x0A717, 0x0A71F,
-    0x0A722, 0x0A788,
-    0x0A78B, 0x0A7BF,
-    0x0A7C2, 0x0A7C6,
-    0x0A7F7, 0x0A801,
-    0x0A803, 0x0A805,
-    0x0A807, 0x0A80A,
-    0x0A80C, 0x0A822,
-    0x0A840, 0x0A873,
-    0x0A882, 0x0A8B3,
-    0x0A8F2, 0x0A8F7,
-    0x0A8FD, 0x0A8FE,
-    0x0A90A, 0x0A925,
-    0x0A930, 0x0A946,
-    0x0A960, 0x0A97C,
-    0x0A984, 0x0A9B2,
-    0x0A9E0, 0x0A9E4,
-    0x0A9E6, 0x0A9EF,
-    0x0A9FA, 0x0A9FE,
-    0x0AA00, 0x0AA28,
-    0x0AA40, 0x0AA42,
-    0x0AA44, 0x0AA4B,
-    0x0AA60, 0x0AA76,
-    0x0AA7E, 0x0AAAF,
-    0x0AAB5, 0x0AAB6,
-    0x0AAB9, 0x0AABD,
-    0x0AADB, 0x0AADD,
-    0x0AAE0, 0x0AAEA,
-    0x0AAF2, 0x0AAF4,
-    0x0AB01, 0x0AB06,
-    0x0AB09, 0x0AB0E,
-    0x0AB11, 0x0AB16,
-    0x0AB20, 0x0AB26,
-    0x0AB28, 0x0AB2E,
-    0x0AB30, 0x0AB5A,
-    0x0AB5C, 0x0AB67,
-    0x0AB70, 0x0ABE2,
-    0x0D7B0, 0x0D7C6,
-    0x0D7CB, 0x0D7FB,
-    0x0F900, 0x0FA6D,
-    0x0FA70, 0x0FAD9,
-    0x0FB00, 0x0FB06,
-    0x0FB13, 0x0FB17,
-    0x0FB1F, 0x0FB28,
-    0x0FB2A, 0x0FB36,
-    0x0FB38, 0x0FB3C,
-    0x0FB40, 0x0FB41,
-    0x0FB43, 0x0FB44,
-    0x0FB46, 0x0FBB1,
-    0x0FBD3, 0x0FD3D,
-    0x0FD50, 0x0FD8F,
-    0x0FD92, 0x0FDC7,
-    0x0FDF0, 0x0FDFB,
-    0x0FE70, 0x0FE74,
-    0x0FE76, 0x0FEFC,
-    0x0FF21, 0x0FF3A,
-    0x0FF41, 0x0FF5A,
-    0x0FF66, 0x0FFBE,
-    0x0FFC2, 0x0FFC7,
-    0x0FFCA, 0x0FFCF,
-    0x0FFD2, 0x0FFD7,
-    0x0FFDA, 0x0FFDC,
-    0x10000, 0x1000B,
-    0x1000D, 0x10026,
-    0x10028, 0x1003A,
-    0x1003C, 0x1003D,
-    0x1003F, 0x1004D,
-    0x10050, 0x1005D,
-    0x10080, 0x100FA,
-    0x10280, 0x1029C,
-    0x102A0, 0x102D0,
-    0x10300, 0x1031F,
-    0x1032D, 0x10340,
-    0x10342, 0x10349,
-    0x10350, 0x10375,
-    0x10380, 0x1039D,
-    0x103A0, 0x103C3,
-    0x103C8, 0x103CF,
-    0x10400, 0x1049D,
-    0x104B0, 0x104D3,
-    0x104D8, 0x104FB,
-    0x10500, 0x10527,
-    0x10530, 0x10563,
-    0x10600, 0x10736,
-    0x10740, 0x10755,
-    0x10760, 0x10767,
-    0x10800, 0x10805,
-    0x1080A, 0x10835,
-    0x10837, 0x10838,
-    0x1083F, 0x10855,
-    0x10860, 0x10876,
-    0x10880, 0x1089E,
-    0x108E0, 0x108F2,
-    0x108F4, 0x108F5,
-    0x10900, 0x10915,
-    0x10920, 0x10939,
-    0x10980, 0x109B7,
-    0x109BE, 0x109BF,
-    0x10A10, 0x10A13,
-    0x10A15, 0x10A17,
-    0x10A19, 0x10A35,
-    0x10A60, 0x10A7C,
-    0x10A80, 0x10A9C,
-    0x10AC0, 0x10AC7,
-    0x10AC9, 0x10AE4,
-    0x10B00, 0x10B35,
-    0x10B40, 0x10B55,
-    0x10B60, 0x10B72,
-    0x10B80, 0x10B91,
-    0x10C00, 0x10C48,
-    0x10C80, 0x10CB2,
-    0x10CC0, 0x10CF2,
-    0x10D00, 0x10D23,
-    0x10F00, 0x10F1C,
-    0x10F30, 0x10F45,
-    0x10FE0, 0x10FF6,
-    0x11003, 0x11037,
-    0x11083, 0x110AF,
-    0x110D0, 0x110E8,
-    0x11103, 0x11126,
-    0x11150, 0x11172,
-    0x11183, 0x111B2,
-    0x111C1, 0x111C4,
-    0x11200, 0x11211,
-    0x11213, 0x1122B,
-    0x11280, 0x11286,
-    0x1128A, 0x1128D,
-    0x1128F, 0x1129D,
-    0x1129F, 0x112A8,
-    0x112B0, 0x112DE,
-    0x11305, 0x1130C,
-    0x1130F, 0x11310,
-    0x11313, 0x11328,
-    0x1132A, 0x11330,
-    0x11332, 0x11333,
-    0x11335, 0x11339,
-    0x1135D, 0x11361,
-    0x11400, 0x11434,
-    0x11447, 0x1144A,
-    0x11480, 0x114AF,
-    0x114C4, 0x114C5,
-    0x11580, 0x115AE,
-    0x115D8, 0x115DB,
-    0x11600, 0x1162F,
-    0x11680, 0x116AA,
-    0x11700, 0x1171A,
-    0x11800, 0x1182B,
-    0x118A0, 0x118DF,
-    0x119A0, 0x119A7,
-    0x119AA, 0x119D0,
-    0x11A0B, 0x11A32,
-    0x11A5C, 0x11A89,
-    0x11AC0, 0x11AF8,
-    0x11C00, 0x11C08,
-    0x11C0A, 0x11C2E,
-    0x11C72, 0x11C8F,
-    0x11D00, 0x11D06,
-    0x11D08, 0x11D09,
-    0x11D0B, 0x11D30,
-    0x11D60, 0x11D65,
-    0x11D67, 0x11D68,
-    0x11D6A, 0x11D89,
-    0x11EE0, 0x11EF2,
-    0x12000, 0x12399,
-    0x12480, 0x12543,
-    0x13000, 0x1342E,
-    0x14400, 0x14646,
-    0x16800, 0x16A38,
-    0x16A40, 0x16A5E,
-    0x16AD0, 0x16AED,
-    0x16B00, 0x16B2F,
-    0x16B40, 0x16B43,
-    0x16B63, 0x16B77,
-    0x16B7D, 0x16B8F,
-    0x16E40, 0x16E7F,
-    0x16F00, 0x16F4A,
-    0x16F93, 0x16F9F,
-    0x16FE0, 0x16FE1,
-    0x18800, 0x18AF2,
-    0x1B000, 0x1B11E,
-    0x1B150, 0x1B152,
-    0x1B164, 0x1B167,
-    0x1B170, 0x1B2FB,
-    0x1BC00, 0x1BC6A,
-    0x1BC70, 0x1BC7C,
-    0x1BC80, 0x1BC88,
-    0x1BC90, 0x1BC99,
-    0x1D400, 0x1D454,
-    0x1D456, 0x1D49C,
-    0x1D49E, 0x1D49F,
-    0x1D4A5, 0x1D4A6,
-    0x1D4A9, 0x1D4AC,
-    0x1D4AE, 0x1D4B9,
-    0x1D4BD, 0x1D4C3,
-    0x1D4C5, 0x1D505,
-    0x1D507, 0x1D50A,
-    0x1D50D, 0x1D514,
-    0x1D516, 0x1D51C,
-    0x1D51E, 0x1D539,
-    0x1D53B, 0x1D53E,
-    0x1D540, 0x1D544,
-    0x1D54A, 0x1D550,
-    0x1D552, 0x1D6A5,
-    0x1D6A8, 0x1D6C0,
-    0x1D6C2, 0x1D6DA,
-    0x1D6DC, 0x1D6FA,
-    0x1D6FC, 0x1D714,
-    0x1D716, 0x1D734,
-    0x1D736, 0x1D74E,
-    0x1D750, 0x1D76E,
-    0x1D770, 0x1D788,
-    0x1D78A, 0x1D7A8,
-    0x1D7AA, 0x1D7C2,
-    0x1D7C4, 0x1D7CB,
-    0x1E100, 0x1E12C,
-    0x1E137, 0x1E13D,
-    0x1E2C0, 0x1E2EB,
-    0x1E800, 0x1E8C4,
-    0x1E900, 0x1E943,
-    0x1EE00, 0x1EE03,
-    0x1EE05, 0x1EE1F,
-    0x1EE21, 0x1EE22,
-    0x1EE29, 0x1EE32,
-    0x1EE34, 0x1EE37,
-    0x1EE4D, 0x1EE4F,
-    0x1EE51, 0x1EE52,
-    0x1EE61, 0x1EE62,
-    0x1EE67, 0x1EE6A,
-    0x1EE6C, 0x1EE72,
-    0x1EE74, 0x1EE77,
-    0x1EE79, 0x1EE7C,
-    0x1EE80, 0x1EE89,
-    0x1EE8B, 0x1EE9B,
-    0x1EEA1, 0x1EEA3,
-    0x1EEA5, 0x1EEA9,
-    0x1EEAB, 0x1EEBB,
-    0x2F800, 0x2FA1D,
+    0x00041'i32, 0x0005A'i32,
+    0x00061'i32, 0x0007A'i32,
+    0x000C0'i32, 0x000D6'i32,
+    0x000D8'i32, 0x000F6'i32,
+    0x000F8'i32, 0x002C1'i32,
+    0x002C6'i32, 0x002D1'i32,
+    0x002E0'i32, 0x002E4'i32,
+    0x00370'i32, 0x00374'i32,
+    0x00376'i32, 0x00377'i32,
+    0x0037A'i32, 0x0037D'i32,
+    0x00388'i32, 0x0038A'i32,
+    0x0038E'i32, 0x003A1'i32,
+    0x003A3'i32, 0x003F5'i32,
+    0x003F7'i32, 0x00481'i32,
+    0x0048A'i32, 0x0052F'i32,
+    0x00531'i32, 0x00556'i32,
+    0x00560'i32, 0x00588'i32,
+    0x005D0'i32, 0x005EA'i32,
+    0x005EF'i32, 0x005F2'i32,
+    0x00620'i32, 0x0064A'i32,
+    0x0066E'i32, 0x0066F'i32,
+    0x00671'i32, 0x006D3'i32,
+    0x006E5'i32, 0x006E6'i32,
+    0x006EE'i32, 0x006EF'i32,
+    0x006FA'i32, 0x006FC'i32,
+    0x00712'i32, 0x0072F'i32,
+    0x0074D'i32, 0x007A5'i32,
+    0x007CA'i32, 0x007EA'i32,
+    0x007F4'i32, 0x007F5'i32,
+    0x00800'i32, 0x00815'i32,
+    0x00840'i32, 0x00858'i32,
+    0x00860'i32, 0x0086A'i32,
+    0x008A0'i32, 0x008B4'i32,
+    0x008B6'i32, 0x008BD'i32,
+    0x00904'i32, 0x00939'i32,
+    0x00958'i32, 0x00961'i32,
+    0x00971'i32, 0x00980'i32,
+    0x00985'i32, 0x0098C'i32,
+    0x0098F'i32, 0x00990'i32,
+    0x00993'i32, 0x009A8'i32,
+    0x009AA'i32, 0x009B0'i32,
+    0x009B6'i32, 0x009B9'i32,
+    0x009DC'i32, 0x009DD'i32,
+    0x009DF'i32, 0x009E1'i32,
+    0x009F0'i32, 0x009F1'i32,
+    0x00A05'i32, 0x00A0A'i32,
+    0x00A0F'i32, 0x00A10'i32,
+    0x00A13'i32, 0x00A28'i32,
+    0x00A2A'i32, 0x00A30'i32,
+    0x00A32'i32, 0x00A33'i32,
+    0x00A35'i32, 0x00A36'i32,
+    0x00A38'i32, 0x00A39'i32,
+    0x00A59'i32, 0x00A5C'i32,
+    0x00A72'i32, 0x00A74'i32,
+    0x00A85'i32, 0x00A8D'i32,
+    0x00A8F'i32, 0x00A91'i32,
+    0x00A93'i32, 0x00AA8'i32,
+    0x00AAA'i32, 0x00AB0'i32,
+    0x00AB2'i32, 0x00AB3'i32,
+    0x00AB5'i32, 0x00AB9'i32,
+    0x00AE0'i32, 0x00AE1'i32,
+    0x00B05'i32, 0x00B0C'i32,
+    0x00B0F'i32, 0x00B10'i32,
+    0x00B13'i32, 0x00B28'i32,
+    0x00B2A'i32, 0x00B30'i32,
+    0x00B32'i32, 0x00B33'i32,
+    0x00B35'i32, 0x00B39'i32,
+    0x00B5C'i32, 0x00B5D'i32,
+    0x00B5F'i32, 0x00B61'i32,
+    0x00B85'i32, 0x00B8A'i32,
+    0x00B8E'i32, 0x00B90'i32,
+    0x00B92'i32, 0x00B95'i32,
+    0x00B99'i32, 0x00B9A'i32,
+    0x00B9E'i32, 0x00B9F'i32,
+    0x00BA3'i32, 0x00BA4'i32,
+    0x00BA8'i32, 0x00BAA'i32,
+    0x00BAE'i32, 0x00BB9'i32,
+    0x00C05'i32, 0x00C0C'i32,
+    0x00C0E'i32, 0x00C10'i32,
+    0x00C12'i32, 0x00C28'i32,
+    0x00C2A'i32, 0x00C39'i32,
+    0x00C58'i32, 0x00C5A'i32,
+    0x00C60'i32, 0x00C61'i32,
+    0x00C85'i32, 0x00C8C'i32,
+    0x00C8E'i32, 0x00C90'i32,
+    0x00C92'i32, 0x00CA8'i32,
+    0x00CAA'i32, 0x00CB3'i32,
+    0x00CB5'i32, 0x00CB9'i32,
+    0x00CE0'i32, 0x00CE1'i32,
+    0x00CF1'i32, 0x00CF2'i32,
+    0x00D05'i32, 0x00D0C'i32,
+    0x00D0E'i32, 0x00D10'i32,
+    0x00D12'i32, 0x00D3A'i32,
+    0x00D54'i32, 0x00D56'i32,
+    0x00D5F'i32, 0x00D61'i32,
+    0x00D7A'i32, 0x00D7F'i32,
+    0x00D85'i32, 0x00D96'i32,
+    0x00D9A'i32, 0x00DB1'i32,
+    0x00DB3'i32, 0x00DBB'i32,
+    0x00DC0'i32, 0x00DC6'i32,
+    0x00E01'i32, 0x00E30'i32,
+    0x00E32'i32, 0x00E33'i32,
+    0x00E40'i32, 0x00E46'i32,
+    0x00E81'i32, 0x00E82'i32,
+    0x00E86'i32, 0x00E8A'i32,
+    0x00E8C'i32, 0x00EA3'i32,
+    0x00EA7'i32, 0x00EB0'i32,
+    0x00EB2'i32, 0x00EB3'i32,
+    0x00EC0'i32, 0x00EC4'i32,
+    0x00EDC'i32, 0x00EDF'i32,
+    0x00F40'i32, 0x00F47'i32,
+    0x00F49'i32, 0x00F6C'i32,
+    0x00F88'i32, 0x00F8C'i32,
+    0x01000'i32, 0x0102A'i32,
+    0x01050'i32, 0x01055'i32,
+    0x0105A'i32, 0x0105D'i32,
+    0x01065'i32, 0x01066'i32,
+    0x0106E'i32, 0x01070'i32,
+    0x01075'i32, 0x01081'i32,
+    0x010A0'i32, 0x010C5'i32,
+    0x010D0'i32, 0x010FA'i32,
+    0x010FC'i32, 0x01248'i32,
+    0x0124A'i32, 0x0124D'i32,
+    0x01250'i32, 0x01256'i32,
+    0x0125A'i32, 0x0125D'i32,
+    0x01260'i32, 0x01288'i32,
+    0x0128A'i32, 0x0128D'i32,
+    0x01290'i32, 0x012B0'i32,
+    0x012B2'i32, 0x012B5'i32,
+    0x012B8'i32, 0x012BE'i32,
+    0x012C2'i32, 0x012C5'i32,
+    0x012C8'i32, 0x012D6'i32,
+    0x012D8'i32, 0x01310'i32,
+    0x01312'i32, 0x01315'i32,
+    0x01318'i32, 0x0135A'i32,
+    0x01380'i32, 0x0138F'i32,
+    0x013A0'i32, 0x013F5'i32,
+    0x013F8'i32, 0x013FD'i32,
+    0x01401'i32, 0x0166C'i32,
+    0x0166F'i32, 0x0167F'i32,
+    0x01681'i32, 0x0169A'i32,
+    0x016A0'i32, 0x016EA'i32,
+    0x016F1'i32, 0x016F8'i32,
+    0x01700'i32, 0x0170C'i32,
+    0x0170E'i32, 0x01711'i32,
+    0x01720'i32, 0x01731'i32,
+    0x01740'i32, 0x01751'i32,
+    0x01760'i32, 0x0176C'i32,
+    0x0176E'i32, 0x01770'i32,
+    0x01780'i32, 0x017B3'i32,
+    0x01820'i32, 0x01878'i32,
+    0x01880'i32, 0x01884'i32,
+    0x01887'i32, 0x018A8'i32,
+    0x018B0'i32, 0x018F5'i32,
+    0x01900'i32, 0x0191E'i32,
+    0x01950'i32, 0x0196D'i32,
+    0x01970'i32, 0x01974'i32,
+    0x01980'i32, 0x019AB'i32,
+    0x019B0'i32, 0x019C9'i32,
+    0x01A00'i32, 0x01A16'i32,
+    0x01A20'i32, 0x01A54'i32,
+    0x01B05'i32, 0x01B33'i32,
+    0x01B45'i32, 0x01B4B'i32,
+    0x01B83'i32, 0x01BA0'i32,
+    0x01BAE'i32, 0x01BAF'i32,
+    0x01BBA'i32, 0x01BE5'i32,
+    0x01C00'i32, 0x01C23'i32,
+    0x01C4D'i32, 0x01C4F'i32,
+    0x01C5A'i32, 0x01C7D'i32,
+    0x01C80'i32, 0x01C88'i32,
+    0x01C90'i32, 0x01CBA'i32,
+    0x01CBD'i32, 0x01CBF'i32,
+    0x01CE9'i32, 0x01CEC'i32,
+    0x01CEE'i32, 0x01CF3'i32,
+    0x01CF5'i32, 0x01CF6'i32,
+    0x01D00'i32, 0x01DBF'i32,
+    0x01E00'i32, 0x01F15'i32,
+    0x01F18'i32, 0x01F1D'i32,
+    0x01F20'i32, 0x01F45'i32,
+    0x01F48'i32, 0x01F4D'i32,
+    0x01F50'i32, 0x01F57'i32,
+    0x01F5F'i32, 0x01F7D'i32,
+    0x01F80'i32, 0x01FB4'i32,
+    0x01FB6'i32, 0x01FBC'i32,
+    0x01FC2'i32, 0x01FC4'i32,
+    0x01FC6'i32, 0x01FCC'i32,
+    0x01FD0'i32, 0x01FD3'i32,
+    0x01FD6'i32, 0x01FDB'i32,
+    0x01FE0'i32, 0x01FEC'i32,
+    0x01FF2'i32, 0x01FF4'i32,
+    0x01FF6'i32, 0x01FFC'i32,
+    0x02090'i32, 0x0209C'i32,
+    0x0210A'i32, 0x02113'i32,
+    0x02119'i32, 0x0211D'i32,
+    0x0212A'i32, 0x0212D'i32,
+    0x0212F'i32, 0x02139'i32,
+    0x0213C'i32, 0x0213F'i32,
+    0x02145'i32, 0x02149'i32,
+    0x02183'i32, 0x02184'i32,
+    0x02C00'i32, 0x02C2E'i32,
+    0x02C30'i32, 0x02C5E'i32,
+    0x02C60'i32, 0x02CE4'i32,
+    0x02CEB'i32, 0x02CEE'i32,
+    0x02CF2'i32, 0x02CF3'i32,
+    0x02D00'i32, 0x02D25'i32,
+    0x02D30'i32, 0x02D67'i32,
+    0x02D80'i32, 0x02D96'i32,
+    0x02DA0'i32, 0x02DA6'i32,
+    0x02DA8'i32, 0x02DAE'i32,
+    0x02DB0'i32, 0x02DB6'i32,
+    0x02DB8'i32, 0x02DBE'i32,
+    0x02DC0'i32, 0x02DC6'i32,
+    0x02DC8'i32, 0x02DCE'i32,
+    0x02DD0'i32, 0x02DD6'i32,
+    0x02DD8'i32, 0x02DDE'i32,
+    0x03005'i32, 0x03006'i32,
+    0x03031'i32, 0x03035'i32,
+    0x0303B'i32, 0x0303C'i32,
+    0x03041'i32, 0x03096'i32,
+    0x0309D'i32, 0x0309F'i32,
+    0x030A1'i32, 0x030FA'i32,
+    0x030FC'i32, 0x030FF'i32,
+    0x03105'i32, 0x0312F'i32,
+    0x03131'i32, 0x0318E'i32,
+    0x031A0'i32, 0x031BA'i32,
+    0x031F0'i32, 0x031FF'i32,
+    0x03400'i32, 0x04DB5'i32,
+    0x04E00'i32, 0x09FEF'i32,
+    0x0A000'i32, 0x0A48C'i32,
+    0x0A4D0'i32, 0x0A4FD'i32,
+    0x0A500'i32, 0x0A60C'i32,
+    0x0A610'i32, 0x0A61F'i32,
+    0x0A62A'i32, 0x0A62B'i32,
+    0x0A640'i32, 0x0A66E'i32,
+    0x0A67F'i32, 0x0A69D'i32,
+    0x0A6A0'i32, 0x0A6E5'i32,
+    0x0A717'i32, 0x0A71F'i32,
+    0x0A722'i32, 0x0A788'i32,
+    0x0A78B'i32, 0x0A7BF'i32,
+    0x0A7C2'i32, 0x0A7C6'i32,
+    0x0A7F7'i32, 0x0A801'i32,
+    0x0A803'i32, 0x0A805'i32,
+    0x0A807'i32, 0x0A80A'i32,
+    0x0A80C'i32, 0x0A822'i32,
+    0x0A840'i32, 0x0A873'i32,
+    0x0A882'i32, 0x0A8B3'i32,
+    0x0A8F2'i32, 0x0A8F7'i32,
+    0x0A8FD'i32, 0x0A8FE'i32,
+    0x0A90A'i32, 0x0A925'i32,
+    0x0A930'i32, 0x0A946'i32,
+    0x0A960'i32, 0x0A97C'i32,
+    0x0A984'i32, 0x0A9B2'i32,
+    0x0A9E0'i32, 0x0A9E4'i32,
+    0x0A9E6'i32, 0x0A9EF'i32,
+    0x0A9FA'i32, 0x0A9FE'i32,
+    0x0AA00'i32, 0x0AA28'i32,
+    0x0AA40'i32, 0x0AA42'i32,
+    0x0AA44'i32, 0x0AA4B'i32,
+    0x0AA60'i32, 0x0AA76'i32,
+    0x0AA7E'i32, 0x0AAAF'i32,
+    0x0AAB5'i32, 0x0AAB6'i32,
+    0x0AAB9'i32, 0x0AABD'i32,
+    0x0AADB'i32, 0x0AADD'i32,
+    0x0AAE0'i32, 0x0AAEA'i32,
+    0x0AAF2'i32, 0x0AAF4'i32,
+    0x0AB01'i32, 0x0AB06'i32,
+    0x0AB09'i32, 0x0AB0E'i32,
+    0x0AB11'i32, 0x0AB16'i32,
+    0x0AB20'i32, 0x0AB26'i32,
+    0x0AB28'i32, 0x0AB2E'i32,
+    0x0AB30'i32, 0x0AB5A'i32,
+    0x0AB5C'i32, 0x0AB67'i32,
+    0x0AB70'i32, 0x0ABE2'i32,
+    0x0AC00'i32, 0x0D7A3'i32,
+    0x0D7B0'i32, 0x0D7C6'i32,
+    0x0D7CB'i32, 0x0D7FB'i32,
+    0x0F900'i32, 0x0FA6D'i32,
+    0x0FA70'i32, 0x0FAD9'i32,
+    0x0FB00'i32, 0x0FB06'i32,
+    0x0FB13'i32, 0x0FB17'i32,
+    0x0FB1F'i32, 0x0FB28'i32,
+    0x0FB2A'i32, 0x0FB36'i32,
+    0x0FB38'i32, 0x0FB3C'i32,
+    0x0FB40'i32, 0x0FB41'i32,
+    0x0FB43'i32, 0x0FB44'i32,
+    0x0FB46'i32, 0x0FBB1'i32,
+    0x0FBD3'i32, 0x0FD3D'i32,
+    0x0FD50'i32, 0x0FD8F'i32,
+    0x0FD92'i32, 0x0FDC7'i32,
+    0x0FDF0'i32, 0x0FDFB'i32,
+    0x0FE70'i32, 0x0FE74'i32,
+    0x0FE76'i32, 0x0FEFC'i32,
+    0x0FF21'i32, 0x0FF3A'i32,
+    0x0FF41'i32, 0x0FF5A'i32,
+    0x0FF66'i32, 0x0FFBE'i32,
+    0x0FFC2'i32, 0x0FFC7'i32,
+    0x0FFCA'i32, 0x0FFCF'i32,
+    0x0FFD2'i32, 0x0FFD7'i32,
+    0x0FFDA'i32, 0x0FFDC'i32,
+    0x10000'i32, 0x1000B'i32,
+    0x1000D'i32, 0x10026'i32,
+    0x10028'i32, 0x1003A'i32,
+    0x1003C'i32, 0x1003D'i32,
+    0x1003F'i32, 0x1004D'i32,
+    0x10050'i32, 0x1005D'i32,
+    0x10080'i32, 0x100FA'i32,
+    0x10280'i32, 0x1029C'i32,
+    0x102A0'i32, 0x102D0'i32,
+    0x10300'i32, 0x1031F'i32,
+    0x1032D'i32, 0x10340'i32,
+    0x10342'i32, 0x10349'i32,
+    0x10350'i32, 0x10375'i32,
+    0x10380'i32, 0x1039D'i32,
+    0x103A0'i32, 0x103C3'i32,
+    0x103C8'i32, 0x103CF'i32,
+    0x10400'i32, 0x1049D'i32,
+    0x104B0'i32, 0x104D3'i32,
+    0x104D8'i32, 0x104FB'i32,
+    0x10500'i32, 0x10527'i32,
+    0x10530'i32, 0x10563'i32,
+    0x10600'i32, 0x10736'i32,
+    0x10740'i32, 0x10755'i32,
+    0x10760'i32, 0x10767'i32,
+    0x10800'i32, 0x10805'i32,
+    0x1080A'i32, 0x10835'i32,
+    0x10837'i32, 0x10838'i32,
+    0x1083F'i32, 0x10855'i32,
+    0x10860'i32, 0x10876'i32,
+    0x10880'i32, 0x1089E'i32,
+    0x108E0'i32, 0x108F2'i32,
+    0x108F4'i32, 0x108F5'i32,
+    0x10900'i32, 0x10915'i32,
+    0x10920'i32, 0x10939'i32,
+    0x10980'i32, 0x109B7'i32,
+    0x109BE'i32, 0x109BF'i32,
+    0x10A10'i32, 0x10A13'i32,
+    0x10A15'i32, 0x10A17'i32,
+    0x10A19'i32, 0x10A35'i32,
+    0x10A60'i32, 0x10A7C'i32,
+    0x10A80'i32, 0x10A9C'i32,
+    0x10AC0'i32, 0x10AC7'i32,
+    0x10AC9'i32, 0x10AE4'i32,
+    0x10B00'i32, 0x10B35'i32,
+    0x10B40'i32, 0x10B55'i32,
+    0x10B60'i32, 0x10B72'i32,
+    0x10B80'i32, 0x10B91'i32,
+    0x10C00'i32, 0x10C48'i32,
+    0x10C80'i32, 0x10CB2'i32,
+    0x10CC0'i32, 0x10CF2'i32,
+    0x10D00'i32, 0x10D23'i32,
+    0x10F00'i32, 0x10F1C'i32,
+    0x10F30'i32, 0x10F45'i32,
+    0x10FE0'i32, 0x10FF6'i32,
+    0x11003'i32, 0x11037'i32,
+    0x11083'i32, 0x110AF'i32,
+    0x110D0'i32, 0x110E8'i32,
+    0x11103'i32, 0x11126'i32,
+    0x11150'i32, 0x11172'i32,
+    0x11183'i32, 0x111B2'i32,
+    0x111C1'i32, 0x111C4'i32,
+    0x11200'i32, 0x11211'i32,
+    0x11213'i32, 0x1122B'i32,
+    0x11280'i32, 0x11286'i32,
+    0x1128A'i32, 0x1128D'i32,
+    0x1128F'i32, 0x1129D'i32,
+    0x1129F'i32, 0x112A8'i32,
+    0x112B0'i32, 0x112DE'i32,
+    0x11305'i32, 0x1130C'i32,
+    0x1130F'i32, 0x11310'i32,
+    0x11313'i32, 0x11328'i32,
+    0x1132A'i32, 0x11330'i32,
+    0x11332'i32, 0x11333'i32,
+    0x11335'i32, 0x11339'i32,
+    0x1135D'i32, 0x11361'i32,
+    0x11400'i32, 0x11434'i32,
+    0x11447'i32, 0x1144A'i32,
+    0x11480'i32, 0x114AF'i32,
+    0x114C4'i32, 0x114C5'i32,
+    0x11580'i32, 0x115AE'i32,
+    0x115D8'i32, 0x115DB'i32,
+    0x11600'i32, 0x1162F'i32,
+    0x11680'i32, 0x116AA'i32,
+    0x11700'i32, 0x1171A'i32,
+    0x11800'i32, 0x1182B'i32,
+    0x118A0'i32, 0x118DF'i32,
+    0x119A0'i32, 0x119A7'i32,
+    0x119AA'i32, 0x119D0'i32,
+    0x11A0B'i32, 0x11A32'i32,
+    0x11A5C'i32, 0x11A89'i32,
+    0x11AC0'i32, 0x11AF8'i32,
+    0x11C00'i32, 0x11C08'i32,
+    0x11C0A'i32, 0x11C2E'i32,
+    0x11C72'i32, 0x11C8F'i32,
+    0x11D00'i32, 0x11D06'i32,
+    0x11D08'i32, 0x11D09'i32,
+    0x11D0B'i32, 0x11D30'i32,
+    0x11D60'i32, 0x11D65'i32,
+    0x11D67'i32, 0x11D68'i32,
+    0x11D6A'i32, 0x11D89'i32,
+    0x11EE0'i32, 0x11EF2'i32,
+    0x12000'i32, 0x12399'i32,
+    0x12480'i32, 0x12543'i32,
+    0x13000'i32, 0x1342E'i32,
+    0x14400'i32, 0x14646'i32,
+    0x16800'i32, 0x16A38'i32,
+    0x16A40'i32, 0x16A5E'i32,
+    0x16AD0'i32, 0x16AED'i32,
+    0x16B00'i32, 0x16B2F'i32,
+    0x16B40'i32, 0x16B43'i32,
+    0x16B63'i32, 0x16B77'i32,
+    0x16B7D'i32, 0x16B8F'i32,
+    0x16E40'i32, 0x16E7F'i32,
+    0x16F00'i32, 0x16F4A'i32,
+    0x16F93'i32, 0x16F9F'i32,
+    0x16FE0'i32, 0x16FE1'i32,
+    0x17000'i32, 0x187F7'i32,
+    0x18800'i32, 0x18AF2'i32,
+    0x1B000'i32, 0x1B11E'i32,
+    0x1B150'i32, 0x1B152'i32,
+    0x1B164'i32, 0x1B167'i32,
+    0x1B170'i32, 0x1B2FB'i32,
+    0x1BC00'i32, 0x1BC6A'i32,
+    0x1BC70'i32, 0x1BC7C'i32,
+    0x1BC80'i32, 0x1BC88'i32,
+    0x1BC90'i32, 0x1BC99'i32,
+    0x1D400'i32, 0x1D454'i32,
+    0x1D456'i32, 0x1D49C'i32,
+    0x1D49E'i32, 0x1D49F'i32,
+    0x1D4A5'i32, 0x1D4A6'i32,
+    0x1D4A9'i32, 0x1D4AC'i32,
+    0x1D4AE'i32, 0x1D4B9'i32,
+    0x1D4BD'i32, 0x1D4C3'i32,
+    0x1D4C5'i32, 0x1D505'i32,
+    0x1D507'i32, 0x1D50A'i32,
+    0x1D50D'i32, 0x1D514'i32,
+    0x1D516'i32, 0x1D51C'i32,
+    0x1D51E'i32, 0x1D539'i32,
+    0x1D53B'i32, 0x1D53E'i32,
+    0x1D540'i32, 0x1D544'i32,
+    0x1D54A'i32, 0x1D550'i32,
+    0x1D552'i32, 0x1D6A5'i32,
+    0x1D6A8'i32, 0x1D6C0'i32,
+    0x1D6C2'i32, 0x1D6DA'i32,
+    0x1D6DC'i32, 0x1D6FA'i32,
+    0x1D6FC'i32, 0x1D714'i32,
+    0x1D716'i32, 0x1D734'i32,
+    0x1D736'i32, 0x1D74E'i32,
+    0x1D750'i32, 0x1D76E'i32,
+    0x1D770'i32, 0x1D788'i32,
+    0x1D78A'i32, 0x1D7A8'i32,
+    0x1D7AA'i32, 0x1D7C2'i32,
+    0x1D7C4'i32, 0x1D7CB'i32,
+    0x1E100'i32, 0x1E12C'i32,
+    0x1E137'i32, 0x1E13D'i32,
+    0x1E2C0'i32, 0x1E2EB'i32,
+    0x1E800'i32, 0x1E8C4'i32,
+    0x1E900'i32, 0x1E943'i32,
+    0x1EE00'i32, 0x1EE03'i32,
+    0x1EE05'i32, 0x1EE1F'i32,
+    0x1EE21'i32, 0x1EE22'i32,
+    0x1EE29'i32, 0x1EE32'i32,
+    0x1EE34'i32, 0x1EE37'i32,
+    0x1EE4D'i32, 0x1EE4F'i32,
+    0x1EE51'i32, 0x1EE52'i32,
+    0x1EE61'i32, 0x1EE62'i32,
+    0x1EE67'i32, 0x1EE6A'i32,
+    0x1EE6C'i32, 0x1EE72'i32,
+    0x1EE74'i32, 0x1EE77'i32,
+    0x1EE79'i32, 0x1EE7C'i32,
+    0x1EE80'i32, 0x1EE89'i32,
+    0x1EE8B'i32, 0x1EE9B'i32,
+    0x1EEA1'i32, 0x1EEA3'i32,
+    0x1EEA5'i32, 0x1EEA9'i32,
+    0x1EEAB'i32, 0x1EEBB'i32,
+    0x20000'i32, 0x2A6D6'i32,
+    0x2A700'i32, 0x2B734'i32,
+    0x2B740'i32, 0x2B81D'i32,
+    0x2B820'i32, 0x2CEA1'i32,
+    0x2CEB0'i32, 0x2EBE0'i32,
+    0x2F800'i32, 0x2FA1D'i32,
   ]
 
   alphaSinglets = [
     0x000AA'i32,
-    0x000B5,
-    0x000BA,
-    0x002EC,
-    0x002EE,
-    0x0037F,
-    0x00386,
-    0x0038C,
-    0x00559,
-    0x006D5,
-    0x006FF,
-    0x00710,
-    0x007B1,
-    0x007FA,
-    0x0081A,
-    0x00824,
-    0x00828,
-    0x0093D,
-    0x00950,
-    0x009B2,
-    0x009BD,
-    0x009CE,
-    0x009FC,
-    0x00A5E,
-    0x00ABD,
-    0x00AD0,
-    0x00AF9,
-    0x00B3D,
-    0x00B71,
-    0x00B83,
-    0x00B9C,
-    0x00BD0,
-    0x00C3D,
-    0x00C80,
-    0x00CBD,
-    0x00CDE,
-    0x00D3D,
-    0x00D4E,
-    0x00DBD,
-    0x00E84,
-    0x00EA5,
-    0x00EBD,
-    0x00EC6,
-    0x00F00,
-    0x0103F,
-    0x01061,
-    0x0108E,
-    0x010C7,
-    0x010CD,
-    0x01258,
-    0x012C0,
-    0x017D7,
-    0x017DC,
-    0x018AA,
-    0x01AA7,
-    0x01CFA,
-    0x01F59,
-    0x01F5B,
-    0x01F5D,
-    0x01FBE,
-    0x02071,
-    0x0207F,
-    0x02102,
-    0x02107,
-    0x02115,
-    0x02124,
-    0x02126,
-    0x02128,
-    0x0214E,
-    0x02D27,
-    0x02D2D,
-    0x02D6F,
-    0x02E2F,
-    0x03400,
-    0x04DB5,
-    0x04E00,
-    0x09FEF,
-    0x0A8FB,
-    0x0A9CF,
-    0x0AA7A,
-    0x0AAB1,
-    0x0AAC0,
-    0x0AAC2,
-    0x0AC00,
-    0x0D7A3,
-    0x0FB1D,
-    0x0FB3E,
-    0x10808,
-    0x1083C,
-    0x10A00,
-    0x10F27,
-    0x11144,
-    0x11176,
-    0x111DA,
-    0x111DC,
-    0x11288,
-    0x1133D,
-    0x11350,
-    0x1145F,
-    0x114C7,
-    0x11644,
-    0x116B8,
-    0x118FF,
-    0x119E1,
-    0x119E3,
-    0x11A00,
-    0x11A3A,
-    0x11A50,
-    0x11A9D,
-    0x11C40,
-    0x11D46,
-    0x11D98,
-    0x16F50,
-    0x16FE3,
-    0x17000,
-    0x187F7,
-    0x1D4A2,
-    0x1D4BB,
-    0x1D546,
-    0x1E14E,
-    0x1E94B,
-    0x1EE24,
-    0x1EE27,
-    0x1EE39,
-    0x1EE3B,
-    0x1EE42,
-    0x1EE47,
-    0x1EE49,
-    0x1EE4B,
-    0x1EE54,
-    0x1EE57,
-    0x1EE59,
-    0x1EE5B,
-    0x1EE5D,
-    0x1EE5F,
-    0x1EE64,
-    0x1EE7E,
-    0x20000,
-    0x2A6D6,
-    0x2A700,
-    0x2B734,
-    0x2B740,
-    0x2B81D,
-    0x2B820,
-    0x2CEA1,
-    0x2CEB0,
-    0x2EBE0,
+    0x000B5'i32,
+    0x000BA'i32,
+    0x002EC'i32,
+    0x002EE'i32,
+    0x0037F'i32,
+    0x00386'i32,
+    0x0038C'i32,
+    0x00559'i32,
+    0x006D5'i32,
+    0x006FF'i32,
+    0x00710'i32,
+    0x007B1'i32,
+    0x007FA'i32,
+    0x0081A'i32,
+    0x00824'i32,
+    0x00828'i32,
+    0x0093D'i32,
+    0x00950'i32,
+    0x009B2'i32,
+    0x009BD'i32,
+    0x009CE'i32,
+    0x009FC'i32,
+    0x00A5E'i32,
+    0x00ABD'i32,
+    0x00AD0'i32,
+    0x00AF9'i32,
+    0x00B3D'i32,
+    0x00B71'i32,
+    0x00B83'i32,
+    0x00B9C'i32,
+    0x00BD0'i32,
+    0x00C3D'i32,
+    0x00C80'i32,
+    0x00CBD'i32,
+    0x00CDE'i32,
+    0x00D3D'i32,
+    0x00D4E'i32,
+    0x00DBD'i32,
+    0x00E84'i32,
+    0x00EA5'i32,
+    0x00EBD'i32,
+    0x00EC6'i32,
+    0x00F00'i32,
+    0x0103F'i32,
+    0x01061'i32,
+    0x0108E'i32,
+    0x010C7'i32,
+    0x010CD'i32,
+    0x01258'i32,
+    0x012C0'i32,
+    0x017D7'i32,
+    0x017DC'i32,
+    0x018AA'i32,
+    0x01AA7'i32,
+    0x01CFA'i32,
+    0x01F59'i32,
+    0x01F5B'i32,
+    0x01F5D'i32,
+    0x01FBE'i32,
+    0x02071'i32,
+    0x0207F'i32,
+    0x02102'i32,
+    0x02107'i32,
+    0x02115'i32,
+    0x02124'i32,
+    0x02126'i32,
+    0x02128'i32,
+    0x0214E'i32,
+    0x02D27'i32,
+    0x02D2D'i32,
+    0x02D6F'i32,
+    0x02E2F'i32,
+    0x0A8FB'i32,
+    0x0A9CF'i32,
+    0x0AA7A'i32,
+    0x0AAB1'i32,
+    0x0AAC0'i32,
+    0x0AAC2'i32,
+    0x0FB1D'i32,
+    0x0FB3E'i32,
+    0x10808'i32,
+    0x1083C'i32,
+    0x10A00'i32,
+    0x10F27'i32,
+    0x11144'i32,
+    0x11176'i32,
+    0x111DA'i32,
+    0x111DC'i32,
+    0x11288'i32,
+    0x1133D'i32,
+    0x11350'i32,
+    0x1145F'i32,
+    0x114C7'i32,
+    0x11644'i32,
+    0x116B8'i32,
+    0x118FF'i32,
+    0x119E1'i32,
+    0x119E3'i32,
+    0x11A00'i32,
+    0x11A3A'i32,
+    0x11A50'i32,
+    0x11A9D'i32,
+    0x11C40'i32,
+    0x11D46'i32,
+    0x11D98'i32,
+    0x16F50'i32,
+    0x16FE3'i32,
+    0x1D4A2'i32,
+    0x1D4BB'i32,
+    0x1D546'i32,
+    0x1E14E'i32,
+    0x1E94B'i32,
+    0x1EE24'i32,
+    0x1EE27'i32,
+    0x1EE39'i32,
+    0x1EE3B'i32,
+    0x1EE42'i32,
+    0x1EE47'i32,
+    0x1EE49'i32,
+    0x1EE4B'i32,
+    0x1EE54'i32,
+    0x1EE57'i32,
+    0x1EE59'i32,
+    0x1EE5B'i32,
+    0x1EE5D'i32,
+    0x1EE5F'i32,
+    0x1EE64'i32,
+    0x1EE7E'i32,
   ]
 
   spaceRanges = [
-    0x00009'i32, 0x0000D,
-    0x00020, 0x00020,
-    0x00085, 0x00085,
-    0x000A0, 0x000A0,
-    0x01680, 0x01680,
-    0x02000, 0x0200A,
-    0x02028, 0x02029,
-    0x0202F, 0x0202F,
-    0x0205F, 0x0205F,
-    0x03000, 0x03000,
+    0x00009'i32, 0x0000D'i32,
+    0x00020'i32, 0x00020'i32,
+    0x00085'i32, 0x00085'i32,
+    0x000A0'i32, 0x000A0'i32,
+    0x01680'i32, 0x01680'i32,
+    0x02000'i32, 0x0200A'i32,
+    0x02028'i32, 0x02029'i32,
+    0x0202F'i32, 0x0202F'i32,
+    0x0205F'i32, 0x0205F'i32,
+    0x03000'i32, 0x03000'i32,
   ]
 
   unicodeSpaces = [
diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim
index e28218a97..513578eda 100644
--- a/lib/pure/ioselects/ioselectors_kqueue.nim
+++ b/lib/pure/ioselects/ioselectors_kqueue.nim
@@ -194,7 +194,9 @@ when hasThreadSupport:
         if s.changesLength > 0:
           if kevent(s.kqFD, addr(s.changes[0]), cint(s.changesLength),
                     nil, 0, nil) == -1:
-            raiseIOSelectorsError(osLastError())
+            let res = osLastError()
+            if cint(res) != ENOENT: # ignore pipes whose read end is closed
+              raiseIOSelectorsError(res)
           s.changesLength = 0
 else:
   template modifyKQueue[T](s: Selector[T], nident: uint, nfilter: cshort,
@@ -211,7 +213,9 @@ else:
       if length > 0:
         if kevent(s.kqFD, addr(s.changes[0]), length,
                   nil, 0, nil) == -1:
-          raiseIOSelectorsError(osLastError())
+          let res = osLastError()
+          if cint(res) != ENOENT: # ignore pipes whose read end is closed
+            raiseIOSelectorsError(res)
         s.changes.setLen(0)
 
 proc registerHandle*[T](s: Selector[T], fd: int | SocketHandle,
diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim
index 11bc62b78..6c516395b 100644
--- a/lib/pure/ioselects/ioselectors_select.nim
+++ b/lib/pure/ioselects/ioselectors_select.nim
@@ -314,7 +314,7 @@ proc selectInto*[T](s: Selector[T], timeout: int,
 
   if timeout != -1:
     when defined(genode) or defined(freertos) or defined(zephyr) or defined(nuttx):
-      tv.tv_sec = Time(timeout div 1_000)
+      tv.tv_sec = posix.Time(timeout div 1_000)
     else:
       tv.tv_sec = timeout.int32 div 1_000
     tv.tv_usec = (timeout.int32 %% 1_000) * 1_000
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 485b8918c..53fa7553a 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1007,7 +1007,7 @@ when defined(js):
       {.emit: """for (var property in `x`) {
         if (`x`.hasOwnProperty(property)) {
       """.}
-      
+
       var nimProperty: cstring
       var nimValue: JsObject
       {.emit: "`nimProperty` = property; `nimValue` = `x`[property];".}
diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim
index 1b6b2b3a2..1efd97b24 100644
--- a/lib/pure/lexbase.nim
+++ b/lib/pure/lexbase.nim
@@ -104,9 +104,9 @@ proc fillBaseLexer(L: var BaseLexer, pos: int): int =
     result = 0
 
 proc handleCR*(L: var BaseLexer, pos: int): int =
-  ## Call this if you scanned over '\c' in the buffer; it returns the
+  ## Call this if you scanned over `'\c'` in the buffer; it returns the
   ## position to continue the scanning from. `pos` must be the position
-  ## of the '\c'.
+  ## of the `'\c'`.
   assert(L.buf[pos] == '\c')
   inc(L.lineNumber)
   result = fillBaseLexer(L, pos)
@@ -115,9 +115,9 @@ proc handleCR*(L: var BaseLexer, pos: int): int =
   L.lineStart = result
 
 proc handleLF*(L: var BaseLexer, pos: int): int =
-  ## Call this if you scanned over '\L' in the buffer; it returns the
+  ## Call this if you scanned over `'\L'` in the buffer; it returns the
   ## position to continue the scanning from. `pos` must be the position
-  ## of the '\L'.
+  ## of the `'\L'`.
   assert(L.buf[pos] == '\L')
   inc(L.lineNumber)
   result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index e3f0240a2..c30f68af8 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -839,6 +839,7 @@ proc addHandler*(handler: Logger) =
   ##   each of those threads.
   ##
   ## See also:
+  ## * `removeHandler proc`_
   ## * `getHandlers proc<#getHandlers>`_
   runnableExamples:
     var logger = newConsoleLogger()
@@ -846,6 +847,16 @@ proc addHandler*(handler: Logger) =
     doAssert logger in getHandlers()
   handlers.add(handler)
 
+proc removeHandler*(handler: Logger) =
+  ## Removes a logger from the list of registered handlers.
+  ##
+  ## Note that for n times a logger is registered, n calls to this proc
+  ## are required to remove that logger.
+  for i, hnd in handlers:
+    if hnd == handler:
+      handlers.delete(i)
+      return
+
 proc getHandlers*(): seq[Logger] =
   ## Returns a list of all the registered handlers.
   ##
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index 1ca4825a2..ed7d2382f 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -58,12 +58,13 @@ import std/private/since
                        # of the standard library!
 
 import std/[bitops, fenv]
+import system/countbits_impl
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
 
 
-when defined(c) or defined(cpp):
+when not defined(js) and not defined(nimscript): # C
   proc c_isnan(x: float): bool {.importc: "isnan", header: "<math.h>".}
     # a generic like `x: SomeFloat` might work too if this is implemented via a C macro.
 
@@ -155,7 +156,7 @@ func fac*(n: int): int =
 
 {.push checks: off, line_dir: off, stack_trace: off.}
 
-when defined(posix) and not defined(genode):
+when defined(posix) and not defined(genode) and not defined(macosx):
   {.passl: "-lm".}
 
 const
@@ -224,7 +225,7 @@ when defined(js):
       return (num & ~(1 << bitPos)) | (bitVal << bitPos);
     }
     `b`[1] = updateBit(`b`[1], 31, `sgn`);
-    `result` = `a`[0]
+    `result` = `a`[0];
     """.}
 
 proc signbit*(x: SomeFloat): bool {.inline, since: (1, 5, 1).} =
@@ -1229,40 +1230,42 @@ func gcd*[T](x, y: T): T =
     swap x, y
   abs x
 
-func gcd*(x, y: SomeInteger): SomeInteger =
-  ## Computes the greatest common (positive) divisor of `x` and `y`,
-  ## using the binary GCD (aka Stein's) algorithm.
-  ##
-  ## **See also:**
-  ## * `gcd func <#gcd,T,T>`_ for a float version
-  ## * `lcm func <#lcm,T,T>`_
-  runnableExamples:
-    doAssert gcd(12, 8) == 4
-    doAssert gcd(17, 63) == 1
-
-  when x is SomeSignedInt:
-    var x = abs(x)
-  else:
-    var x = x
-  when y is SomeSignedInt:
-    var y = abs(y)
-  else:
-    var y = y
-
-  if x == 0:
-    return y
-  if y == 0:
-    return x
-
-  let shift = countTrailingZeroBits(x or y)
-  y = y shr countTrailingZeroBits(y)
-  while x != 0:
-    x = x shr countTrailingZeroBits(x)
-    if y > x:
-      swap y, x
-    x -= y
-  y shl shift
-
+when useBuiltins:
+  ## this func uses bitwise comparisons from C compilers, which are not always available.
+  func gcd*(x, y: SomeInteger): SomeInteger =
+    ## Computes the greatest common (positive) divisor of `x` and `y`,
+    ## using the binary GCD (aka Stein's) algorithm.
+    ##
+    ## **See also:**
+    ## * `gcd func <#gcd,T,T>`_ for a float version
+    ## * `lcm func <#lcm,T,T>`_
+    runnableExamples:
+      doAssert gcd(12, 8) == 4
+      doAssert gcd(17, 63) == 1
+  
+    when x is SomeSignedInt:
+      var x = abs(x)
+    else:
+      var x = x
+    when y is SomeSignedInt:
+      var y = abs(y)
+    else:
+      var y = y
+  
+    if x == 0:
+      return y
+    if y == 0:
+      return x
+  
+    let shift = countTrailingZeroBits(x or y)
+    y = y shr countTrailingZeroBits(y)
+    while x != 0:
+      x = x shr countTrailingZeroBits(x)
+      if y > x:
+        swap y, x
+      x -= y
+    y shl shift
+  
 func gcd*[T](x: openArray[T]): T {.since: (1, 1).} =
   ## Computes the greatest common (positive) divisor of the elements of `x`.
   ##
diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim
index c65a9c2da..9c3f6d51b 100644
--- a/lib/pure/md5.nim
+++ b/lib/pure/md5.nim
@@ -100,32 +100,19 @@ proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
     dest[i+3] = uint8(src[j] shr 24 and 0xff'u32)
     inc(i, 4)
 
-template slice(s: string, a, b): openArray[uint8] =
-  when nimvm:
-    # toOpenArray is not implemented in VM
-    var s2 = newSeq[uint8](s.len)
-    for i in 0 ..< s2.len:
-      s2[i] = uint8(s[i])
-    s2
-  else:
-    s.toOpenArrayByte(a, b)
-
 template slice(s: cstring, a, b): openArray[uint8] =
   when nimvm:
     # toOpenArray is not implemented in VM
-    slice($s, a, b)
+    toOpenArrayByte($s, a, b)
   else:
     when defined(js):
       # toOpenArrayByte for cstring is not implemented in JS
-      slice($s, a, b)
+      toOpenArrayByte($s, a, b)
     else:
       s.toOpenArrayByte(a, b)
 
 template slice(s: openArray[uint8], a, b): openArray[uint8] =
-  when nimvm:
-    s[a .. b]
-  else:
-    s.toOpenArray(a, b)
+  s.toOpenArray(a, b)
 
 const useMem = declared(copyMem)
 
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index df5b8c46f..8eec551c4 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -35,12 +35,12 @@ proc newEIO(msg: string): ref IOError =
   new(result)
   result.msg = msg
 
-proc setFileSize(fh: FileHandle, newFileSize = -1): OSErrorCode =
-  ## Set the size of open file pointed to by `fh` to `newFileSize` if != -1.
-  ## Space is only allocated if that is cheaper than writing to the file.  This
-  ## routine returns the last OSErrorCode found rather than raising to support
-  ## old rollback/clean-up code style. [ Should maybe move to std/osfiles. ]
-  if newFileSize == -1:
+proc setFileSize(fh: FileHandle, newFileSize = -1, oldSize = -1): OSErrorCode =
+  ## Set the size of open file pointed to by `fh` to `newFileSize` if != -1,
+  ## allocating | freeing space from the file system.  This routine returns the
+  ## last OSErrorCode found rather than raising to support old rollback/clean-up
+  ## code style. [ Should maybe move to std/osfiles. ]
+  if newFileSize < 0 or newFileSize == oldSize:
     return
   when defined(windows):
     var sizeHigh = int32(newFileSize shr 32)
@@ -51,14 +51,18 @@ proc setFileSize(fh: FileHandle, newFileSize = -1): OSErrorCode =
         setEndOfFile(fh) == 0:
       result = lastErr
   else:
-    var e: cint # posix_fallocate truncates up when needed.
-    when declared(posix_fallocate):
-      while (e = posix_fallocate(fh, 0, newFileSize); e == EINTR):
-        discard
-    if e in [EINVAL, EOPNOTSUPP] and ftruncate(fh, newFileSize) == -1:
-      result = osLastError() # fallback arguable; Most portable, but allows SEGV
-    elif e != 0:
-      result = osLastError()
+    if newFileSize > oldSize: # grow the file
+      var e: cint # posix_fallocate truncates up when needed.
+      when declared(posix_fallocate):
+        while (e = posix_fallocate(fh, 0, newFileSize); e == EINTR):
+          discard
+      if e in [EINVAL, EOPNOTSUPP] and ftruncate(fh, newFileSize) == -1:
+        result = osLastError() # fallback arguable; Most portable BUT allows SEGV
+      elif e != 0:
+        result = osLastError()
+    else: # shrink the file
+      if ftruncate(fh.cint, newFileSize) == -1:
+        result = osLastError()
 
 type
   MemFile* = object      ## represents a memory mapped file
@@ -255,41 +259,31 @@ proc open*(filename: string, mode: FileMode = fmRead,
       flags = flags or O_CREAT or O_TRUNC
       var permissionsMode = S_IRUSR or S_IWUSR
       result.handle = open(filename, flags, permissionsMode)
+      if result.handle != -1:
+        if (let e = setFileSize(result.handle.FileHandle, newFileSize);
+            e != 0.OSErrorCode): fail(e, "error setting file size")
     else:
       result.handle = open(filename, flags)
 
     if result.handle == -1:
-      # XXX: errno is supposed to be set here
-      # Is there an exception that wraps it?
       fail(osLastError(), "error opening file")
 
-    if (let e = setFileSize(result.handle.FileHandle, newFileSize);
-        e != 0.OSErrorCode): fail(e, "error setting file size")
-
-    if mappedSize != -1:
-      result.size = mappedSize
-    else:
-      var stat: Stat
+    if mappedSize != -1: #XXX Logic here differs from `when windows` branch ..
+      result.size = mappedSize #.. which always fstats&Uses min(mappedSize, st).
+    else: # if newFileSize!=-1: result.size=newFileSize # if trust setFileSize
+      var stat: Stat  #^^.. BUT some FSes (eg. Linux HugeTLBfs) round to 2MiB.
       if fstat(result.handle, stat) != -1:
-        # XXX: Hmm, this could be unsafe
-        # Why is mmap taking int anyway?
-        result.size = int(stat.st_size)
+        result.size = stat.st_size.int # int may be 32-bit-unsafe for 2..<4 GiB
       else:
         fail(osLastError(), "error getting file size")
 
     result.flags = if mapFlags == cint(-1): MAP_SHARED else: mapFlags
-    #Ensure exactly one of MAP_PRIVATE cr MAP_SHARED is set
+    # Ensure exactly one of MAP_PRIVATE cr MAP_SHARED is set
     if int(result.flags and MAP_PRIVATE) == 0:
       result.flags = result.flags or MAP_SHARED
 
-    result.mem = mmap(
-      nil,
-      result.size,
-      if readonly: PROT_READ else: PROT_READ or PROT_WRITE,
-      result.flags,
-      result.handle,
-      offset)
-
+    let pr = if readonly: PROT_READ else: PROT_READ or PROT_WRITE
+    result.mem = mmap(nil, result.size, pr, result.flags, result.handle, offset)
     if result.mem == cast[pointer](MAP_FAILED):
       fail(osLastError(), "file mapping failed")
 
@@ -353,7 +347,7 @@ proc resize*(f: var MemFile, newFileSize: int) {.raises: [IOError, OSError].} =
       raise newException(IOError,
                          "Cannot resize MemFile opened with allowRemap=false")
     if newFileSize != f.size:
-      if (let e = setFileSize(f.handle.FileHandle, newFileSize);
+      if (let e = setFileSize(f.handle.FileHandle, newFileSize, f.size);
           e != 0.OSErrorCode): raiseOSError(e)
     when defined(linux): #Maybe NetBSD, too?
       # On Linux this can be over 100 times faster than a munmap,mmap cycle.
@@ -418,7 +412,7 @@ proc `==`*(x, y: MemSlice): bool =
 proc `$`*(ms: MemSlice): string {.inline.} =
   ## Return a Nim string built from a MemSlice.
   result.setLen(ms.size)
-  copyMem(addr(result[0]), ms.data, ms.size)
+  copyMem(result.cstring, ms.data, ms.size)
 
 iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline.} =
   ## Iterates over \[optional `eat`] `delim`-delimited slices in MemFile `mfile`.
diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim
index e1ad94a57..ff639e8e5 100644
--- a/lib/pure/mimetypes.nim
+++ b/lib/pure/mimetypes.nim
@@ -432,6 +432,10 @@ const mimes* = {
   "msty": "application/vnd.muvee.style",
   "taglet": "application/vnd.mynfc",
   "nlu": "application/vnd.neurolanguage.nlu",
+  "nim": "text/nim",
+  "nimble": "text/nimble",
+  "nimf": "text/nim",
+  "nims": "text/nim",
   "ntf": "application/vnd.nitf",
   "nitf": "application/vnd.nitf",
   "nnd": "application/vnd.noblenet-directory",
diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim
index 20ea9d77a..656c98a20 100644
--- a/lib/pure/nativesockets.nim
+++ b/lib/pure/nativesockets.nim
@@ -97,6 +97,8 @@ type
     length*: int
     addrList*: seq[string]
 
+const IPPROTO_NONE* = IPPROTO_IP ## Use this if your socket type requires a protocol value of zero (e.g. Unix sockets).
+
 when useWinVersion:
   let
     osInvalidSocket* = winlean.INVALID_SOCKET
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index d77ab5db1..24c94b651 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -97,7 +97,7 @@ import std/nativesockets
 import std/[os, strutils, times, sets, options, monotimes]
 import std/ssl_config
 export nativesockets.Port, nativesockets.`$`, nativesockets.`==`
-export Domain, SockType, Protocol
+export Domain, SockType, Protocol, IPPROTO_NONE
 
 const useWinVersion = defined(windows) or defined(nimdoc)
 const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) or
@@ -1321,7 +1321,7 @@ when defined(nimdoc) or (defined(posix) and not useNimNetLite):
     when not defined(nimdoc):
       var socketAddr = makeUnixAddr(path)
       if socket.fd.connect(cast[ptr SockAddr](addr socketAddr),
-          (sizeof(socketAddr.sun_family) + path.len).SockLen) != 0'i32:
+          (offsetOf(socketAddr, sun_path) + path.len + 1).SockLen) != 0'i32:
         raiseOSError(osLastError())
 
   proc bindUnix*(socket: Socket, path: string) =
@@ -1330,7 +1330,7 @@ when defined(nimdoc) or (defined(posix) and not useNimNetLite):
     when not defined(nimdoc):
       var socketAddr = makeUnixAddr(path)
       if socket.fd.bindAddr(cast[ptr SockAddr](addr socketAddr),
-          (sizeof(socketAddr.sun_family) + path.len).SockLen) != 0'i32:
+          (offsetOf(socketAddr, sun_path) + path.len + 1).SockLen) != 0'i32:
         raiseOSError(osLastError())
 
 when defineSsl:
@@ -2040,8 +2040,10 @@ proc dial*(address: string, port: Port,
   if success:
     result = newSocket(lastFd, domain, sockType, protocol, buffered)
   elif lastError != 0.OSErrorCode:
+    lastFd.close()
     raiseOSError(lastError)
   else:
+    lastFd.close()
     raise newException(IOError, "Couldn't resolve address: " & address)
 
 proc connect*(socket: Socket, address: string,
diff --git a/lib/pure/options.nim b/lib/pure/options.nim
index b7a6a6212..b34ff72c0 100644
--- a/lib/pure/options.nim
+++ b/lib/pure/options.nim
@@ -117,9 +117,10 @@ proc option*[T](val: sink T): Option[T] {.inline.} =
     assert option[Foo](nil).isNone
     assert option(42).isSome
 
-  result.val = val
-  when T isnot SomePointer:
-    result.has = true
+  when T is SomePointer:
+    result = Option[T](val: val)
+  else:
+    result = Option[T](has: true, val: val)
 
 proc some*[T](val: sink T): Option[T] {.inline.} =
   ## Returns an `Option` that has the value `val`.
@@ -136,10 +137,9 @@ proc some*[T](val: sink T): Option[T] {.inline.} =
 
   when T is SomePointer:
     assert not val.isNil
-    result.val = val
+    result = Option[T](val: val)
   else:
-    result.has = true
-    result.val = val
+    result = Option[T](has: true, val: val)
 
 proc none*(T: typedesc): Option[T] {.inline.} =
   ## Returns an `Option` for this type that has no value.
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 3afb9cdd7..78ebb1c88 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -692,7 +692,10 @@ proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noWeirdT
 
 proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noWeirdTarget.} =
   ## Sleeps `milsecs` milliseconds.
+  ## A negative `milsecs` causes sleep to return immediately.
   when defined(windows):
+    if milsecs < 0:
+      return  # fixes #23732
     winlean.sleep(int32(milsecs))
   else:
     var a, b: Timespec
@@ -754,14 +757,14 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
   ## 'rawInfo' is either a 'BY_HANDLE_FILE_INFORMATION' structure on Windows,
   ## or a 'Stat' structure on posix
   when defined(windows):
-    template merge(a, b): untyped =
-      int64(
+    template merge[T](a, b): untyped =
+       cast[T](
         (uint64(cast[uint32](a))) or
         (uint64(cast[uint32](b)) shl 32)
        )
     formalInfo.id.device = rawInfo.dwVolumeSerialNumber
-    formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
-    formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)
+    formalInfo.id.file = merge[FileId](rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
+    formalInfo.size = merge[BiggestInt](rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)
     formalInfo.linkCount = rawInfo.nNumberOfLinks
     formalInfo.lastAccessTime = fromWinTime(rdFileTime(rawInfo.ftLastAccessTime))
     formalInfo.lastWriteTime = fromWinTime(rdFileTime(rawInfo.ftLastWriteTime))
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 9284e823a..c304ecca6 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -212,7 +212,7 @@ proc processID*(p: Process): int {.rtl, extern: "nosp$1".} =
   return p.id
 
 proc waitForExit*(p: Process, timeout: int = -1): int {.rtl,
-    extern: "nosp$1", raises: [OSError, ValueError], tags: [].}
+    extern: "nosp$1", raises: [OSError, ValueError], tags: [TimeEffect].}
   ## Waits for the process to finish and returns `p`'s error code.
   ##
   ## .. warning:: Be careful when using `waitForExit` for processes created without
@@ -457,7 +457,7 @@ proc execProcesses*(cmds: openArray[string],
       if afterRunEvent != nil: afterRunEvent(i, p)
       close(p)
 
-iterator lines*(p: Process, keepNewLines = false): string {.since: (1, 3), raises: [OSError, IOError, ValueError], tags: [ReadIOEffect].} =
+iterator lines*(p: Process, keepNewLines = false): string {.since: (1, 3), raises: [OSError, IOError, ValueError], tags: [ReadIOEffect, TimeEffect].} =
   ## Convenience iterator for working with `startProcess` to read data from a
   ## background process.
   ##
@@ -487,7 +487,7 @@ iterator lines*(p: Process, keepNewLines = false): string {.since: (1, 3), raise
   discard waitForExit(p)
 
 proc readLines*(p: Process): (seq[string], int) {.since: (1, 3),
-    raises: [OSError, IOError, ValueError], tags: [ReadIOEffect].} =
+    raises: [OSError, IOError, ValueError], tags: [ReadIOEffect, TimeEffect].} =
   ## Convenience function for working with `startProcess` to read data from a
   ## background process.
   ##
@@ -1123,14 +1123,13 @@ elif not defined(useNimRtl):
       var error: cint
       let sizeRead = read(data.pErrorPipe[readIdx], addr error, sizeof(error))
       if sizeRead == sizeof(error):
-        raiseOSError(osLastError(),
+        raiseOSError(OSErrorCode(error),
                       "Could not find command: '" & $data.sysCommand & "'. OS error: " & $strerror(error))
 
       return pid
 
     {.push stacktrace: off, profiler: off.}
-    proc startProcessFail(data: ptr StartProcessData) =
-      var error: cint = errno
+    proc startProcessFail(data: ptr StartProcessData, error: cint = errno) =
       discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error))
       exitnow(1)
 
@@ -1167,7 +1166,11 @@ elif not defined(useNimRtl):
       if (poUsePath in data.options):
         when defined(uClibc) or defined(linux) or defined(haiku):
           # uClibc environment (OpenWrt included) doesn't have the full execvpe
-          let exe = findExe(data.sysCommand)
+          var exe: string
+          try:
+            exe = findExe(data.sysCommand)
+          except OSError as e:
+            startProcessFail(data, e.errorCode)
           discard execve(exe.cstring, data.sysArgs, data.sysEnv)
         else:
           # MacOSX doesn't have execvpe, so we need workaround.
@@ -1353,114 +1356,63 @@ elif not defined(useNimRtl):
       result = exitStatusLikeShell(p.exitStatus)
 
   else:
-    import std/times
-
-    const
-      hasThreadSupport = compileOption("threads") and not defined(nimscript)
+    import std/times except getTime
+    import std/monotimes
 
     proc waitForExit(p: Process, timeout: int = -1): int =
-      template adjustTimeout(t, s, e: Timespec) =
-        var diff: int
-        var b: Timespec
-        b.tv_sec = e.tv_sec
-        b.tv_nsec = e.tv_nsec
-        e.tv_sec = e.tv_sec - s.tv_sec
-        if e.tv_nsec >= s.tv_nsec:
-          e.tv_nsec -= s.tv_nsec
-        else:
-          if e.tv_sec == posix.Time(0):
-            raise newException(ValueError, "System time was modified")
-          else:
-            diff = s.tv_nsec - e.tv_nsec
-            e.tv_nsec = 1_000_000_000 - diff
-        t.tv_sec = t.tv_sec - e.tv_sec
-        if t.tv_nsec >= e.tv_nsec:
-          t.tv_nsec -= e.tv_nsec
-        else:
-          t.tv_sec = t.tv_sec - posix.Time(1)
-          diff = e.tv_nsec - t.tv_nsec
-          t.tv_nsec = 1_000_000_000 - diff
-        s.tv_sec = b.tv_sec
-        s.tv_nsec = b.tv_nsec
-
       if p.exitFlag:
         return exitStatusLikeShell(p.exitStatus)
 
-      if timeout == -1:
-        var status: cint = 1
+      if timeout < 0:
+        # Backwards compatibility with previous verison to
+        # handle cases where timeout == -1, but extend
+        # to handle cases where timeout < 0
+        var status: cint
         if waitpid(p.id, status, 0) < 0:
           raiseOSError(osLastError())
         p.exitFlag = true
         p.exitStatus = status
       else:
-        var nmask, omask: Sigset
-        var sinfo: SigInfo
-        var stspec, enspec, tmspec: Timespec
-
-        discard sigemptyset(nmask)
-        discard sigemptyset(omask)
-        discard sigaddset(nmask, SIGCHLD)
-
-        when hasThreadSupport:
-          if pthread_sigmask(SIG_BLOCK, nmask, omask) == -1:
-            raiseOSError(osLastError())
-        else:
-          if sigprocmask(SIG_BLOCK, nmask, omask) == -1:
-            raiseOSError(osLastError())
-
-        if timeout >= 1000:
-          tmspec.tv_sec = posix.Time(timeout div 1_000)
-          tmspec.tv_nsec = (timeout %% 1_000) * 1_000_000
-        else:
-          tmspec.tv_sec = posix.Time(0)
-          tmspec.tv_nsec = (timeout * 1_000_000)
-
-        try:
-          if clock_gettime(CLOCK_REALTIME, stspec) == -1:
-            raiseOSError(osLastError())
-          while true:
-            let res = sigtimedwait(nmask, sinfo, tmspec)
-            if res == SIGCHLD:
-              if sinfo.si_pid == p.id:
-                var status: cint = 1
-                if waitpid(p.id, status, 0) < 0:
-                  raiseOSError(osLastError())
-                p.exitFlag = true
-                p.exitStatus = status
-                break
-              else:
-                # we have SIGCHLD, but not for process we are waiting,
-                # so we need to adjust timeout value and continue
-                if clock_gettime(CLOCK_REALTIME, enspec) == -1:
-                  raiseOSError(osLastError())
-                adjustTimeout(tmspec, stspec, enspec)
-            elif res < 0:
-              let err = osLastError()
-              if err.cint == EINTR:
-                # we have received another signal, so we need to
-                # adjust timeout and continue
-                if clock_gettime(CLOCK_REALTIME, enspec) == -1:
-                  raiseOSError(osLastError())
-                adjustTimeout(tmspec, stspec, enspec)
-              elif err.cint == EAGAIN:
-                # timeout expired, so we trying to kill process
-                if posix.kill(p.id, SIGKILL) == -1:
-                  raiseOSError(osLastError())
-                var status: cint = 1
-                if waitpid(p.id, status, 0) < 0:
-                  raiseOSError(osLastError())
-                p.exitFlag = true
-                p.exitStatus = status
-                break
-              else:
-                raiseOSError(err)
-        finally:
-          when hasThreadSupport:
-            if pthread_sigmask(SIG_UNBLOCK, nmask, omask) == -1:
-              raiseOSError(osLastError())
+        # Max 50ms delay
+        const maxWait = initDuration(milliseconds = 50)
+        let wait = initDuration(milliseconds = timeout)
+        let deadline = getMonoTime() + wait
+        # starting 50μs delay
+        var delay = initDuration(microseconds = 50)
+        
+        while true:
+          var status: cint
+          let pid = waitpid(p.id, status, WNOHANG)
+          if p.id == pid :
+            p.exitFlag = true
+            p.exitStatus = status
+            break
+          elif pid.int == -1:
+            raiseOsError(osLastError())
           else:
-            if sigprocmask(SIG_UNBLOCK, nmask, omask) == -1:
-              raiseOSError(osLastError())
+            # Continue waiting if needed
+            if getMonoTime() >= deadline:
+              # Previous version of `waitForExit`
+              # foricibly killed the process.
+              # We keep this so we don't break programs
+              # that depend on this behavior
+              if posix.kill(p.id, SIGKILL) < 0:
+                raiseOSError(osLastError())
+            else:
+              const max = 1_000_000_000
+              let 
+                newWait = getMonoTime() + delay
+                ticks = newWait.ticks()
+                ns = ticks mod max
+                secs = ticks div max
+              var 
+                waitSpec: TimeSpec
+                unused: Timespec
+              waitSpec.tv_sec = posix.Time(secs)
+              waitSpec.tv_nsec = clong ns 
+              discard posix.clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, waitSpec, unused)
+              let remaining = deadline - getMonoTime()
+              delay = min([delay * 2, remaining, maxWait])
 
       result = exitStatusLikeShell(p.exitStatus)
 
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
index 24c903b58..03f151b66 100644
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -176,6 +176,7 @@
 
 include "system/inclrtl"
 
+import std/strutils
 import std/os
 
 type
@@ -249,9 +250,20 @@ proc initOptParser*(cmdline: seq[string], shortNoVal: set[char] = {},
       result.cmds[i] = cmdline[i]
   else:
     when declared(paramCount):
-      result.cmds = newSeq[string](paramCount())
-      for i in countup(1, paramCount()):
-        result.cmds[i-1] = paramStr(i)
+      when defined(nimscript):
+        var ctr = 0
+        var firstNimsFound = false
+        for i in countup(0, paramCount()):
+          if firstNimsFound: 
+            result.cmds[ctr] = paramStr(i)
+            inc ctr, 1
+          if paramStr(i).endsWith(".nims") and not firstNimsFound:
+            firstNimsFound = true 
+            result.cmds = newSeq[string](paramCount()-i)
+      else:
+        result.cmds = newSeq[string](paramCount())
+        for i in countup(1, paramCount()):
+          result.cmds[i-1] = paramStr(i)
     else:
       # we cannot provide this for NimRtl creation on Posix, because we can't
       # access the command line arguments then!
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index ce642fcf7..2ca255fa0 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -460,6 +460,8 @@ proc parseBiggestInt*(s: openArray[char], number: var BiggestInt): int {.
     var res: BiggestInt
     doAssert parseBiggestInt("9223372036854775807", res) == 19
     doAssert res == 9223372036854775807
+    doAssert parseBiggestInt("-2024_05_09", res) == 11
+    doAssert res == -20240509
   var res = BiggestInt(0)
   # use 'res' for exception safety (don't write to 'number' in case of an
   # overflow exception):
@@ -474,10 +476,8 @@ proc parseInt*(s: openArray[char], number: var int): int {.
   ## `ValueError` is raised if the parsed integer is out of the valid range.
   runnableExamples:
     var res: int
-    doAssert parseInt("2019", res, 0) == 4
-    doAssert res == 2019
-    doAssert parseInt("2019", res, 2) == 2
-    doAssert res == 19
+    doAssert parseInt("-2024_05_02", res) == 11
+    doAssert res == -20240502
   var res = BiggestInt(0)
   result = parseBiggestInt(s, res)
   when sizeof(int) <= 4:
@@ -992,6 +992,10 @@ proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.noSid
     var res: BiggestInt
     doAssert parseBiggestInt("9223372036854775807", res, 0) == 19
     doAssert res == 9223372036854775807
+    doAssert parseBiggestInt("-2024_05_09", res) == 11
+    doAssert res == -20240509
+    doAssert parseBiggestInt("-2024_05_02", res, 7) == 4
+    doAssert res == 502
   parseBiggestInt(s.toOpenArray(start, s.high), number)
 
 proc parseInt*(s: string, number: var int, start = 0): int {.noSideEffect, raises: [ValueError].} =
@@ -1000,10 +1004,10 @@ proc parseInt*(s: string, number: var int, start = 0): int {.noSideEffect, raise
   ## `ValueError` is raised if the parsed integer is out of the valid range.
   runnableExamples:
     var res: int
-    doAssert parseInt("2019", res, 0) == 4
-    doAssert res == 2019
-    doAssert parseInt("2019", res, 2) == 2
-    doAssert res == 19
+    doAssert parseInt("-2024_05_02", res) == 11
+    doAssert res == -20240502
+    doAssert parseInt("-2024_05_02", res, 7) == 4
+    doAssert res == 502
   parseInt(s.toOpenArray(start, s.high), number)
 
 
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index ca2e80021..2969fd6d7 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -1047,7 +1047,7 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) =
           `enter hdPostf`(s, pegNode, start)
         else:
           discard
-      let hdPostf = ident(substr(strVal(pegKind), 2))
+      let hdPostf = ident(substr($pegKind, 2))
       getAst(mkDoEnter(hdPostf, s, pegNode, start))
 
     macro leave(pegKind, s, pegNode, start, length: untyped): untyped =
@@ -1058,7 +1058,7 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) =
           `leave hdPostf`(s, pegNode, start, length)
         else:
           discard
-      let hdPostf = ident(substr(strVal(pegKind), 2))
+      let hdPostf = ident(substr($pegKind, 2))
       getAst(mkDoLeave(hdPostf, s, pegNode, start, length))
 
     matchOrParse(parseIt)
diff --git a/lib/pure/random.nim b/lib/pure/random.nim
index 749944376..3ec77d37e 100644
--- a/lib/pure/random.nim
+++ b/lib/pure/random.nim
@@ -79,15 +79,28 @@ when defined(nimPreviewSlimSystem):
 
 include system/inclrtl
 {.push debugger: off.}
+template whenHasBigInt64(yes64, no64): untyped =
+  when defined(js):
+    when compiles(compileOption("jsbigint64")):
+      when compileOption("jsbigint64"):
+        yes64
+      else:
+        no64
+    else:
+      no64
+  else:
+    yes64
 
-when defined(js):
-  type Ui = uint32
 
-  const randMax = 4_294_967_295u32
-else:
+whenHasBigInt64:
   type Ui = uint64
 
   const randMax = 18_446_744_073_709_551_615u64
+do:
+  type Ui = uint32
+
+  const randMax = 4_294_967_295u32
+
 
 type
   Rand* = object ## State of a random number generator.
@@ -105,17 +118,17 @@ type
                  ## generator are **not** thread-safe!
     a0, a1: Ui
 
-when defined(js):
-  var state = Rand(
-    a0: 0x69B4C98Cu32,
-    a1: 0xFED1DD30u32) # global for backwards compatibility
-else:
+whenHasBigInt64:
   const DefaultRandSeed = Rand(
     a0: 0x69B4C98CB8530805u64,
     a1: 0xFED1DD3004688D67CAu64)
 
   # racy for multi-threading but good enough for now:
   var state = DefaultRandSeed # global for backwards compatibility
+do:
+  var state = Rand(
+    a0: 0x69B4C98Cu32,
+    a1: 0xFED1DD30u32) # global for backwards compatibility
 
 func isValid(r: Rand): bool {.inline.} =
   ## Check whether state of `r` is valid.
@@ -208,10 +221,10 @@ proc skipRandomNumbers*(s: var Rand) =
     doAssert vals == [501737, 497901, 500683, 500157]
 
 
-  when defined(js):
-    const helper = [0xbeac0467u32, 0xd86b048bu32]
-  else:
+  whenHasBigInt64:
     const helper = [0xbeac0467eba5facbu64, 0xd86b048b86aa9922u64]
+  do:
+    const helper = [0xbeac0467u32, 0xd86b048bu32]
   var
     s0 = Ui 0
     s1 = Ui 0
@@ -294,7 +307,13 @@ proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} =
 
   let x = next(r)
   when defined(js):
-    result = (float(x) / float(high(uint32))) * max
+    when compiles(compileOption("jsbigint64")):
+      when compileOption("jsbigint64"):
+        result = (float(x) / float(high(uint64))) * max
+      else:
+        result = (float(x) / float(high(uint32))) * max
+    else:
+      result = (float(x) / float(high(uint32))) * max
   else:
     let u = (0x3FFu64 shl 52u64) or (x shr 12u64)
     result = (cast[float](u) - 1.0) * max
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 8ae7fb3c1..56f49d7b1 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -15,6 +15,11 @@
 ## Other modules may provide other implementations for this standard
 ## stream interface.
 ##
+## .. warning:: Due to the use of `pointer`, the `readData`, `peekData` and
+## `writeData` interfaces are not available on the compile-time VM, and must
+## be cast from a `ptr string` on the JS backend. However, `readDataStr` is
+## available generally in place of `readData`.
+##
 ## Basic usage
 ## ===========
 ##
@@ -938,10 +943,14 @@ proc peekFloat64*(s: Stream): float64 =
 
 proc readStrPrivate(s: Stream, length: int, str: var string) =
   if length > len(str): setLen(str, length)
-  when defined(js):
-    let L = readData(s, addr(str), length)
+  var L: int
+  when nimvm:
+    L = readDataStr(s, str, 0..length-1)
   else:
-    let L = readData(s, cstring(str), length)
+    when defined(js):
+      L = readData(s, addr(str), length)
+    else:
+      L = readData(s, cstring(str), length)
   if L != len(str): setLen(str, L)
 
 proc readStr*(s: Stream, length: int, str: var string) {.since: (1, 3).} =
diff --git a/lib/pure/strmisc.nim b/lib/pure/strmisc.nim
index c8cd839be..a3e539e7e 100644
--- a/lib/pure/strmisc.nim
+++ b/lib/pure/strmisc.nim
@@ -27,20 +27,17 @@ func expandTabs*(s: string, tabSize: int = 8): string =
     doAssert expandTabs("a\tb\n\txy\t", 3) == "a  b\n   xy "
 
   result = newStringOfCap(s.len + s.len shr 2)
-  var pos = 0
 
   template addSpaces(n) =
-    for j in 0 ..< n:
+    for _ in 1..n:
       result.add(' ')
-      pos += 1
+    pos += n
 
-  for i in 0 ..< len(s):
-    let c = s[i]
+  var pos = 0
+  let denominator = if tabSize > 0: tabSize else: 1
+  for c in s:
     if c == '\t':
-      let
-        denominator = if tabSize > 0: tabSize else: 1
-        numSpaces = tabSize - pos mod denominator
-
+      let numSpaces = tabSize - pos mod denominator
       addSpaces(numSpaces)
     else:
       result.add(c)
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 741562a6e..81be7db17 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -334,9 +334,9 @@ func normalize*(s: string): string {.rtl, extern: "nsuNormalize".} =
 func cmpIgnoreCase*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreCase".} =
   ## Compares two strings in a case insensitive manner. Returns:
   ##
-  ## | 0 if a == b
-  ## | < 0 if a < b
-  ## | > 0 if a > b
+  ## | `0` if a == b
+  ## | `< 0` if a < b
+  ## | `> 0` if a > b
   runnableExamples:
     doAssert cmpIgnoreCase("FooBar", "foobar") == 0
     doAssert cmpIgnoreCase("bar", "Foo") < 0
@@ -354,9 +354,9 @@ func cmpIgnoreStyle*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreStyle".} =
   ##
   ## Returns:
   ##
-  ## | 0 if a == b
-  ## | < 0 if a < b
-  ## | > 0 if a > b
+  ## | `0` if a == b
+  ## | `< 0` if a < b
+  ## | `> 0` if a > b
   runnableExamples:
     doAssert cmpIgnoreStyle("foo_bar", "FooBar") == 0
     doAssert cmpIgnoreStyle("foo_bar_5", "FooBar4") > 0
@@ -565,7 +565,7 @@ iterator rsplit*(s: string, sep: char,
                  maxsplit: int = -1): string =
   ## Splits the string `s` into substrings from the right using a
   ## string separator. Works exactly the same as `split iterator
-  ## <#split.i,string,char,int>`_ except in reverse order.
+  ## <#split.i,string,char,int>`_ except in **reverse** order.
   ##
   ##   ```nim
   ##   for piece in "foo:bar".rsplit(':'):
@@ -592,7 +592,7 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace,
                  maxsplit: int = -1): string =
   ## Splits the string `s` into substrings from the right using a
   ## string separator. Works exactly the same as `split iterator
-  ## <#split.i,string,char,int>`_ except in reverse order.
+  ## <#split.i,string,char,int>`_ except in **reverse** order.
   ##
   ##   ```nim
   ##   for piece in "foo bar".rsplit(WhiteSpace):
@@ -622,7 +622,7 @@ iterator rsplit*(s: string, sep: string, maxsplit: int = -1,
                  keepSeparators: bool = false): string =
   ## Splits the string `s` into substrings from the right using a
   ## string separator. Works exactly the same as `split iterator
-  ## <#split.i,string,string,int>`_ except in reverse order.
+  ## <#split.i,string,string,int>`_ except in **reverse** order.
   ##
   ##   ```nim
   ##   for piece in "foothebar".rsplit("the"):
@@ -805,7 +805,7 @@ func split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl,
 func rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string] {.rtl,
     extern: "nsuRSplitChar".} =
   ## The same as the `rsplit iterator <#rsplit.i,string,char,int>`_, but is a func
-  ## that returns a sequence of substrings.
+  ## that returns a sequence of substrings in original order.
   ##
   ## A possible common use case for `rsplit` is path manipulation,
   ## particularly on systems that don't use a common delimiter.
@@ -835,7 +835,7 @@ func rsplit*(s: string, seps: set[char] = Whitespace,
              maxsplit: int = -1): seq[string]
              {.rtl, extern: "nsuRSplitCharSet".} =
   ## The same as the `rsplit iterator <#rsplit.i,string,set[char],int>`_, but is a
-  ## func that returns a sequence of substrings.
+  ## func that returns a sequence of substrings in original order.
   ##
   ## A possible common use case for `rsplit` is path manipulation,
   ## particularly on systems that don't use a common delimiter.
@@ -867,7 +867,7 @@ func rsplit*(s: string, seps: set[char] = Whitespace,
 func rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl,
     extern: "nsuRSplitString".} =
   ## The same as the `rsplit iterator <#rsplit.i,string,string,int,bool>`_, but is a func
-  ## that returns a sequence of substrings.
+  ## that returns a sequence of substrings in original order.
   ##
   ## A possible common use case for `rsplit` is path manipulation,
   ## particularly on systems that don't use a common delimiter.
@@ -1307,7 +1307,7 @@ func parseEnum*[T: enum](s: string): T =
   ## type contains multiple fields with the same string value.
   ##
   ## Raises `ValueError` for an invalid value in `s`. The comparison is
-  ## done in a style insensitive way.
+  ## done in a style insensitive way (first letter is still case-sensitive).
   runnableExamples:
     type
       MyEnum = enum
@@ -1327,7 +1327,7 @@ func parseEnum*[T: enum](s: string, default: T): T =
   ## type contains multiple fields with the same string value.
   ##
   ## Uses `default` for an invalid value in `s`. The comparison is done in a
-  ## style insensitive way.
+  ## style insensitive way (first letter is still case-sensitive).
   runnableExamples:
     type
       MyEnum = enum
diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim
index 7833ed063..90ba20c13 100644
--- a/lib/pure/sugar.nim
+++ b/lib/pure/sugar.nim
@@ -203,7 +203,7 @@ proc freshIdentNodes(ast: NimNode): NimNode =
   # see also https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458
   proc inspect(node: NimNode): NimNode =
     case node.kind:
-    of nnkIdent, nnkSym:
+    of nnkIdent, nnkSym, nnkOpenSymChoice, nnkClosedSymChoice, nnkOpenSym:
       result = ident($node)
     of nnkEmpty, nnkLiterals:
       result = node
@@ -345,9 +345,9 @@ proc collectImpl(init, body: NimNode): NimNode {.since: (1, 1).} =
   let res = genSym(nskVar, "collectResult")
   var bracketExpr: NimNode
   if init != nil:
-    expectKind init, {nnkCall, nnkIdent, nnkSym, nnkClosedSymChoice, nnkOpenSymChoice}
+    expectKind init, {nnkCall, nnkIdent, nnkSym, nnkClosedSymChoice, nnkOpenSymChoice, nnkOpenSym}
     bracketExpr = newTree(nnkBracketExpr,
-      if init.kind in {nnkCall, nnkClosedSymChoice, nnkOpenSymChoice}:
+      if init.kind in {nnkCall, nnkClosedSymChoice, nnkOpenSymChoice, nnkOpenSym}:
         freshIdentNodes(init[0]) else: freshIdentNodes(init))
   else:
     bracketExpr = newTree(nnkBracketExpr)
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index a8e24313f..e59153455 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -131,9 +131,10 @@
   ===========  =================================================================================  ==============================================
 
   Other strings can be inserted by putting them in `''`. For example
-  `hh'->'mm` will give `01->56`.  The following characters can be
-  inserted without quoting them: `:` `-` `(` `)` `/` `[` `]`
-  `,`. A literal `'` can be specified with `''`.
+  `hh'->'mm` will give `01->56`.  In addition to spaces,
+  the following characters can be inserted without quoting them:
+  `:` `-` `,` `.` `(` `)` `/` `[` `]`.
+  A literal `'` can be specified with `''`.
 
   However you don't need to necessarily separate format patterns, as an
   unambiguous format string like `yyyyMMddhhmmss` is also valid (although
@@ -1498,11 +1499,11 @@ proc `-=`*(a: var DateTime, b: Duration) =
   a = a - b
 
 proc getDateStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
-  ## Gets the current local date as a string of the format `YYYY-MM-DD`.
+  ## Gets the current local date as a string of the format `YYYY-MM-dd`.
   runnableExamples:
     echo getDateStr(now() - 1.months)
   assertDateTimeInitialized dt
-  result = newStringOfCap(10)  # len("YYYY-MM-DD") == 10
+  result = newStringOfCap(10)  # len("YYYY-MM-dd") == 10
   result.addInt dt.year
   result.add '-'
   result.add intToStr(dt.monthZero, 2)
@@ -1631,7 +1632,7 @@ const
         "Sunday"],
   )
 
-  FormatLiterals = {' ', '-', '/', ':', '(', ')', '[', ']', ','}
+  FormatLiterals = {' ', '-', '/', ':', '(', ')', '[', ']', ',', '.'}
 
 proc `$`*(f: TimeFormat): string =
   ## Returns the format string that was used to construct `f`.
diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim
index 7c58d1ddc..78af84fdd 100644
--- a/lib/pure/typetraits.nim
+++ b/lib/pure/typetraits.nim
@@ -130,6 +130,40 @@ template pointerBase*[T](_: typedesc[ptr T | ref T]): typedesc =
     assert (var s = "abc"; s[0].addr).typeof.pointerBase is char
   T
 
+proc rangeBase*(T: typedesc[range]): typedesc {.magic: "TypeTrait".} =
+  ## Returns the base type for range types, or the type itself otherwise.
+  ##
+  ## **See also:**
+  ## * `rangeBase template <#rangeBase.t,T>`_
+  runnableExamples:
+    type MyRange = range[0..5]
+    type MyEnum = enum a, b, c
+    type MyEnumRange = range[b..c]
+    doAssert rangeBase(MyRange) is int
+    doAssert rangeBase(MyEnumRange) is MyEnum
+    doAssert rangeBase(range['a'..'z']) is char
+
+template rangeBase*[T: range](a: T): untyped =
+  ## Overload of `rangeBase <#rangeBase,typedesc,static[bool]>`_ for values.
+  runnableExamples:
+    type MyRange = range[0..5]
+    type MyEnum = enum a, b, c
+    type MyEnumRange = range[b..c]
+    let x = MyRange(3)
+    doAssert rangeBase(x) is int
+    doAssert $typeof(rangeBase(x)) == "int"
+    doAssert rangeBase(x) == 3
+    let y: set[MyEnumRange] = {c}
+    for e in y:
+      doAssert rangeBase(e) is MyEnum
+      doAssert $typeof(rangeBase(e)) == "MyEnum"
+      doAssert rangeBase(e) == c
+    let z: seq[range['a'..'z']] = @['c']
+    doAssert rangeBase(z[0]) is char
+    doAssert $typeof(rangeBase(z[0])) == "char"
+    doAssert rangeBase(z[0]) == 'c'
+  rangeBase(typeof(T))(a)
+
 proc distinctBase*(T: typedesc, recursive: static bool = true): typedesc {.magic: "TypeTrait".} =
   ## Returns the base type for distinct types, or the type itself otherwise.
   ## If `recursive` is false, only the immediate distinct base will be returned.
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index f329aa1e3..8cbe117bb 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -836,9 +836,9 @@ proc toRunes*(s: openArray[char]): seq[Rune] =
 proc cmpRunesIgnoreCase*(a, b: openArray[char]): int {.rtl, extern: "nuc$1".} =
   ## Compares two UTF-8 strings and ignores the case. Returns:
   ##
-  ## | 0 if a == b
-  ## | < 0 if a < b
-  ## | > 0 if a > b
+  ## | `0` if a == b
+  ## | `< 0` if a < b
+  ## | `> 0` if a > b
   var i = 0
   var j = 0
   var ar, br: Rune
@@ -1375,9 +1375,9 @@ proc toRunes*(s: string): seq[Rune] {.inline.} =
 proc cmpRunesIgnoreCase*(a, b: string): int {.inline.} =
   ## Compares two UTF-8 strings and ignores the case. Returns:
   ##
-  ## | 0 if a == b
-  ## | < 0 if a < b
-  ## | > 0 if a > b
+  ## | `0` if a == b
+  ## | `< 0` if a < b
+  ## | `> 0` if a > b
   cmpRunesIgnoreCase(a.toOa(), b.toOa())
 
 proc reversed*(s: string): string {.inline.} =
diff --git a/lib/pure/volatile.nim b/lib/pure/volatile.nim
index f30d899df..a38247c7d 100644
--- a/lib/pure/volatile.nim
+++ b/lib/pure/volatile.nim
@@ -10,20 +10,18 @@
 ## This module contains code for generating volatile loads and stores,
 ## which are useful in embedded and systems programming.
 
-template volatileLoad*[T](src: ptr T): T =
+proc volatileLoad*[T](src: ptr T): T {.inline, noinit.} =
   ## Generates a volatile load of the value stored in the container `src`.
   ## Note that this only effects code generation on `C` like backends.
   when nimvm:
-    src[]
+    result = src[]
   else:
     when defined(js):
-      src[]
+      result = src[]
     else:
-      var res: T
-      {.emit: [res, " = (*(", typeof(src[]), " volatile*)", src, ");"].}
-      res
+      {.emit: [result, " = (*(", typeof(src[]), " volatile*)", src, ");"].}
 
-template volatileStore*[T](dest: ptr T, val: T) =
+proc volatileStore*[T](dest: ptr T, val: T) {.inline.} =
   ## Generates a volatile store into the container `dest` of the value
   ## `val`. Note that this only effects code generation on `C` like
   ## backends.
diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim
index bcfb2d5d7..9c338817d 100644
--- a/lib/std/enumutils.nim
+++ b/lib/std/enumutils.nim
@@ -174,6 +174,9 @@ template symbolRank*[T: enum](a: T): int =
   when T is Ordinal: ord(a) - T.low.ord.static
   else: symbolRankImpl(a)
 
+proc rangeBase(T: typedesc): typedesc {.magic: "TypeTrait".}
+  # skip one level of range; return the base type of a range type
+
 func symbolName*[T: enum](a: T): string =
   ## Returns the symbol name of an enum.
   ##
@@ -192,5 +195,8 @@ func symbolName*[T: enum](a: T): string =
       c1 = 4
       c2 = 20
     assert c1.symbolName == "c1"
-  const names = enumNames(T)
+  when T is range:
+    const names = enumNames(rangeBase T)
+  else:
+    const names = enumNames(T)
   names[a.symbolRank]
diff --git a/lib/std/formatfloat.nim b/lib/std/formatfloat.nim
index 63d344215..9258245f6 100644
--- a/lib/std/formatfloat.nim
+++ b/lib/std/formatfloat.nim
@@ -109,11 +109,11 @@ when defined(js):
         return n.toString().match(/^-?\d+$/);
       }
       if (Number.isSafeInteger(`a`))
-        `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0"
+        `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0";
       else {
-        `result` = `a`+""
+        `result` = `a`+"";
         if(nimOnlyDigitsOrMinus(`result`)){
-          `result` = `a`+".0"
+          `result` = `a`+".0";
         }
       }
     """.}
diff --git a/lib/std/paths.nim b/lib/std/paths.nim
index b488d2fea..664dedd31 100644
--- a/lib/std/paths.nim
+++ b/lib/std/paths.nim
@@ -9,7 +9,7 @@ export osseps
 import std/envvars
 import std/private/osappdirs
 
-import std/pathnorm
+import std/[pathnorm, hashes, sugar, strutils]
 
 from std/private/ospaths2 import  joinPath, splitPath,
                                   ReadDirEffect, WriteDirEffect,
@@ -25,6 +25,16 @@ export ReadDirEffect, WriteDirEffect
 type
   Path* = distinct string
 
+func hash*(x: Path): Hash =
+  let x = x.string.dup(normalizePath)
+  if FileSystemCaseSensitive:
+    result = x.hash
+  else:
+    result = x.toLowerAscii.hash
+
+template `$`*(x: Path): string =
+  string(x)
+
 func `==`*(x, y: Path): bool {.inline.} =
   ## Compares two paths.
   ##
diff --git a/lib/std/private/jsutils.nim b/lib/std/private/jsutils.nim
index fd1f395f3..5f79eab27 100644
--- a/lib/std/private/jsutils.nim
+++ b/lib/std/private/jsutils.nim
@@ -37,13 +37,13 @@ when defined(js):
       let a = array[2, float64].default
       assert jsConstructorName(a) == "Float64Array"
       assert jsConstructorName(a.toJs) == "Float64Array"
-    asm """`result` = `a`.constructor.name"""
+    {.emit: """`result` = `a`.constructor.name;""".}
 
   proc hasJsBigInt*(): bool =
-    asm """`result` = typeof BigInt != 'undefined'"""
+    {.emit: """`result` = typeof BigInt != 'undefined';""".}
 
   proc hasBigUint64Array*(): bool =
-    asm """`result` = typeof BigUint64Array != 'undefined'"""
+    {.emit: """`result` = typeof BigUint64Array != 'undefined';""".}
 
   proc getProtoName*[T](a: T): cstring {.importjs: "Object.prototype.toString.call(#)".} =
     runnableExamples:
diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim
index b89a59c8d..a44cad7d9 100644
--- a/lib/std/private/osdirs.nim
+++ b/lib/std/private/osdirs.nim
@@ -446,13 +446,17 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1",
     else:
       discard existsOrCreateDir(p)
 
-proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
+proc copyDir*(source, dest: string, skipSpecial = false) {.rtl, extern: "nos$1",
   tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} =
   ## Copies a directory from `source` to `dest`.
   ##
   ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
   ## are skipped.
   ##
+  ## If `skipSpecial` is true, then (besides all directories) only *regular*
+  ## files (**without** special "file" objects like FIFOs, device files,
+  ## etc) will be copied on Unix.
+  ##
   ## If this fails, `OSError` is raised.
   ##
   ## On the Windows platform this proc will copy the attributes from
@@ -472,16 +476,17 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
   ## * `createDir proc`_
   ## * `moveDir proc`_
   createDir(dest)
-  for kind, path in walkDir(source):
+  for kind, path in walkDir(source, skipSpecial = skipSpecial):
     var noSource = splitPath(path).tail
     if kind == pcDir:
-      copyDir(path, dest / noSource)
+      copyDir(path, dest / noSource, skipSpecial = skipSpecial)
     else:
       copyFile(path, dest / noSource, {cfSymlinkAsIs})
 
 
 proc copyDirWithPermissions*(source, dest: string,
-                             ignorePermissionErrors = true)
+                             ignorePermissionErrors = true,
+                             skipSpecial = false)
   {.rtl, extern: "nos$1", tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect],
    benign, noWeirdTarget.} =
   ## Copies a directory from `source` to `dest` preserving file permissions.
@@ -489,6 +494,10 @@ proc copyDirWithPermissions*(source, dest: string,
   ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
   ## are skipped.
   ##
+  ## If `skipSpecial` is true, then (besides all directories) only *regular*
+  ## files (**without** special "file" objects like FIFOs, device files,
+  ## etc) will be copied on Unix.
+  ##
   ## If this fails, `OSError` is raised. This is a wrapper proc around
   ## `copyDir`_ and `copyFileWithPermissions`_ procs
   ## on non-Windows platforms.
@@ -518,10 +527,10 @@ proc copyDirWithPermissions*(source, dest: string,
     except:
       if not ignorePermissionErrors:
         raise
-  for kind, path in walkDir(source):
+  for kind, path in walkDir(source, skipSpecial = skipSpecial):
     var noSource = splitPath(path).tail
     if kind == pcDir:
-      copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors)
+      copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors, skipSpecial = skipSpecial)
     else:
       copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors, {cfSymlinkAsIs})
 
diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim
index a1d7079c5..37d8eabca 100644
--- a/lib/std/private/osfiles.nim
+++ b/lib/std/private/osfiles.nim
@@ -240,7 +240,7 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}; bufferSize = 1
       else:
         # generic version of copyFile which works for any platform:
         var d, s: File
-        if not open(s, source):raiseOSError(osLastError(), source)
+        if not open(s, source): raiseOSError(osLastError(), source)
         if not open(d, dest, fmWrite):
           close(s)
           raiseOSError(osLastError(), dest)
diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim
index a5c0edd9f..bc69ff725 100644
--- a/lib/std/private/ospaths2.nim
+++ b/lib/std/private/ospaths2.nim
@@ -763,9 +763,9 @@ proc cmpPaths*(pathA, pathB: string): int {.
   ## On a case-sensitive filesystem this is done
   ## case-sensitively otherwise case-insensitively. Returns:
   ##
-  ## | 0 if pathA == pathB
-  ## | < 0 if pathA < pathB
-  ## | > 0 if pathA > pathB
+  ## | `0` if pathA == pathB
+  ## | `< 0` if pathA < pathB
+  ## | `> 0` if pathA > pathB
   runnableExamples:
     when defined(macosx):
       assert cmpPaths("foo", "Foo") == 0
diff --git a/lib/std/private/ossymlinks.nim b/lib/std/private/ossymlinks.nim
index c0774b573..c1760c42e 100644
--- a/lib/std/private/ossymlinks.nim
+++ b/lib/std/private/ossymlinks.nim
@@ -66,11 +66,13 @@ proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} =
   when defined(windows) or defined(nintendoswitch):
     result = symlinkPath
   else:
-    result = newString(maxSymlinkLen)
-    var len = readlink(symlinkPath, result.cstring, maxSymlinkLen)
-    if len < 0:
-      raiseOSError(osLastError(), symlinkPath)
-    if len > maxSymlinkLen:
-      result = newString(len+1)
-      len = readlink(symlinkPath, result.cstring, len)
-    setLen(result, len)
+    var bufLen = 1024
+    while true:
+      result = newString(bufLen)
+      let len = readlink(symlinkPath.cstring, result.cstring, bufLen)
+      if len < 0:
+        raiseOSError(osLastError(), symlinkPath)
+      if len < bufLen:
+        result.setLen(len)
+        break
+      bufLen = bufLen shl 1
diff --git a/lib/std/syncio.nim b/lib/std/syncio.nim
index 2b39375ea..c34a025af 100644
--- a/lib/std/syncio.nim
+++ b/lib/std/syncio.nim
@@ -874,7 +874,7 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} =
   var f: File = nil
   if open(f, filename, fmWrite):
     try:
-      f.writeBuffer(unsafeAddr content[0], content.len)
+      discard f.writeBuffer(unsafeAddr content[0], content.len)
     finally:
       close(f)
   else:
diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim
index 1892acd72..7e59747f5 100644
--- a/lib/std/tasks.nim
+++ b/lib/std/tasks.nim
@@ -110,6 +110,19 @@ template addAllNode(assignParam: NimNode, procParam: NimNode) =
   tempAssignList.add newLetStmt(tempNode, newDotExpr(objTemp, formalParams[i][0]))
   scratchRecList.add newIdentDefs(newIdentNode(formalParams[i][0].strVal), assignParam)
 
+proc analyseRootSym(s: NimNode): NimNode =
+  result = s
+  while true:
+    case result.kind
+    of nnkBracketExpr, nnkDerefExpr, nnkHiddenDeref,
+        nnkAddr, nnkHiddenAddr,
+        nnkObjDownConv, nnkObjUpConv:
+      result = result[0]
+    of nnkDotExpr, nnkCheckedFieldExpr, nnkHiddenStdConv, nnkHiddenSubConv:
+      result = result[1]
+    else:
+      break
+
 macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkCallStrLit}): Task =
   ## Converts the call and its arguments to `Task`.
   runnableExamples:
@@ -121,11 +134,14 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC
   let retType = getTypeInst(e)
   let returnsVoid = retType.typeKind == ntyVoid
 
+  let rootSym = analyseRootSym(e[0])
+  expectKind rootSym, nnkSym
+
   when compileOption("threads"):
-    if not isGcSafe(e[0]):
+    if not isGcSafe(rootSym):
       error("'toTask' takes a GC safe call expression", e)
 
-  if hasClosure(e[0]):
+  if hasClosure(rootSym):
     error("closure call is not allowed", e)
 
   if e.len > 1:
@@ -209,7 +225,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC
     let funcCall = newCall(e[0], callNode)
     functionStmtList.add tempAssignList
 
-    let funcName = genSym(nskProc, e[0].strVal)
+    let funcName = genSym(nskProc, rootSym.strVal)
     let destroyName = genSym(nskProc, "destroyScratch")
     let objTemp2 = genSym(ident = "obj")
     let tempNode = quote("@") do:
@@ -241,7 +257,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC
       Task(callback: `funcName`, args: `scratchIdent`, destroy: `destroyName`)
   else:
     let funcCall = newCall(e[0])
-    let funcName = genSym(nskProc, e[0].strVal)
+    let funcName = genSym(nskProc, rootSym.strVal)
 
     if returnsVoid:
       result = quote do:
diff --git a/lib/std/time_t.nim b/lib/std/time_t.nim
index 5fa95fff3..de051b135 100644
--- a/lib/std/time_t.nim
+++ b/lib/std/time_t.nim
@@ -14,7 +14,7 @@ when defined(nimdoc):
       ## Wrapper for `time_t`. On posix, this is an alias to `posix.Time`.
 elif defined(windows):
   when defined(i386) and defined(gcc):
-    type Time* {.importc: "time_t", header: "<time.h>".} = distinct int32
+    type Time* {.importc: "time_t", header: "<time.h>".} = distinct clong
   else:
     # newest version of Visual C++ defines time_t to be of 64 bits
     type Time* {.importc: "time_t", header: "<time.h>".} = distinct int64
diff --git a/lib/std/varints.nim b/lib/std/varints.nim
index 0d18b9069..32fe2fffb 100644
--- a/lib/std/varints.nim
+++ b/lib/std/varints.nim
@@ -82,29 +82,29 @@ proc writeVu64*(z: var openArray[byte], x: uint64): int =
       z[3] = cast[uint8](y)
       return 4
     z[0] = 251
-    varintWrite32(toOpenArray(z, 1, z.high-1), y)
+    varintWrite32(toOpenArray(z, 1, 4), y)
     return 5
   if w <= 255:
     z[0] = 252
     z[1] = cast[uint8](w)
-    varintWrite32(toOpenArray(z, 2, z.high-2), y)
+    varintWrite32(toOpenArray(z, 2, 5), y)
     return 6
   if w <= 65535:
     z[0] = 253
     z[1] = cast[uint8](w shr 8)
     z[2] = cast[uint8](w)
-    varintWrite32(toOpenArray(z, 3, z.high-3), y)
+    varintWrite32(toOpenArray(z, 3, 6), y)
     return 7
   if w <= 16777215:
     z[0] = 254
     z[1] = cast[uint8](w shr 16)
     z[2] = cast[uint8](w shr 8)
     z[3] = cast[uint8](w)
-    varintWrite32(toOpenArray(z, 4, z.high-4), y)
+    varintWrite32(toOpenArray(z, 4, 7), y)
     return 8
   z[0] = 255
-  varintWrite32(toOpenArray(z, 1, z.high-1), w)
-  varintWrite32(toOpenArray(z, 5, z.high-5), y)
+  varintWrite32(toOpenArray(z, 1, 4), w)
+  varintWrite32(toOpenArray(z, 5, 8), y)
   return 9
 
 proc sar(a, b: int64): int64 =
diff --git a/lib/system.nim b/lib/system.nim
index e34538a89..2f9cdc5f9 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -158,9 +158,11 @@ when defined(nimHasEnsureMove):
     ## Ensures that `x` is moved to the new location, otherwise it gives
     ## an error at the compile time.
     runnableExamples:
-      var x = "Hello"
-      let y = ensureMove(x)
-      doAssert y == "Hello"
+      proc foo =
+        var x = "Hello"
+        let y = ensureMove(x)
+        doAssert y == "Hello"
+      foo()
     discard "implemented in injectdestructors"
 
 type
@@ -1035,7 +1037,7 @@ const
     ## Possible values:
     ## `"i386"`, `"alpha"`, `"powerpc"`, `"powerpc64"`, `"powerpc64el"`,
     ## `"sparc"`, `"amd64"`, `"mips"`, `"mipsel"`, `"arm"`, `"arm64"`,
-    ## `"mips64"`, `"mips64el"`, `"riscv32"`, `"riscv64"`, '"loongarch64"'.
+    ## `"mips64"`, `"mips64el"`, `"riscv32"`, `"riscv64"`, `"loongarch64"`.
 
   seqShallowFlag = low(int)
   strlitFlag = 1 shl (sizeof(int)*8 - 2) # later versions of the codegen \
@@ -2083,7 +2085,8 @@ when notJSnotNims:
   proc cmpMem(a, b: pointer, size: Natural): int =
     nimCmpMem(a, b, size).int
 
-when not defined(js):
+when not defined(js) or defined(nimscript):
+  # nimscript can be defined if config file for js compilation
   proc cmp(x, y: string): int =
     when nimvm:
       if x < y: result = -1
@@ -2100,12 +2103,14 @@ when not defined(js):
     proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
       ## Converts a `cstringArray` to a `seq[string]`. `a` is supposed to be
       ## of length `len`.
+      if a == nil: return @[]
       newSeq(result, len)
       for i in 0..len-1: result[i] = $a[i]
 
     proc cstringArrayToSeq*(a: cstringArray): seq[string] =
       ## Converts a `cstringArray` to a `seq[string]`. `a` is supposed to be
       ## terminated by `nil`.
+      if a == nil: return @[]
       var L = 0
       while a[L] != nil: inc(L)
       result = cstringArrayToSeq(a, L)
@@ -2346,8 +2351,14 @@ when notJSnotNims:
     `result` = `x`.ClE_0;
     """.}
 
-  proc finished*[T: iterator {.closure.}](x: T): bool {.noSideEffect, inline, magic: "Finished".} =
-    ## It can be used to determine if a first class iterator has finished.
+proc finished*[T: iterator {.closure.}](x: T): bool {.noSideEffect, inline, magic: "Finished".} =
+  ## It can be used to determine if a first class iterator has finished.
+  when defined(js):
+    # TODO: mangle `:state`
+    {.emit: """
+    `result` = (`x`.ClE_0).HEX3Astate < 0;
+    """.}
+  else:
     {.emit: """
     `result` = ((NI*) `x`.ClE_0)[1] < 0;
     """.}
@@ -2355,7 +2366,8 @@ when notJSnotNims:
 from std/private/digitsutils import addInt
 export addInt
 
-when defined(js):
+when defined(js) and not defined(nimscript):
+  # nimscript can be defined if config file for js compilation
   include "system/jssys"
   include "system/reprjs"
 
@@ -2786,6 +2798,18 @@ when not defined(js):
 
 proc toOpenArray*[T](x: seq[T]; first, last: int): openArray[T] {.
   magic: "Slice".}
+  ## Allows passing the slice of `x` from the element at `first` to the element
+  ## at `last` to `openArray[T]` parameters without copying it.
+  ##
+  ## Example:
+  ##   ```nim
+  ##   proc test(x: openArray[int]) =
+  ##     doAssert x == [1, 2, 3]
+  ##
+  ##   let s = @[0, 1, 2, 3, 4]
+  ##   s.toOpenArray(1, 3).test
+  ##   ```
+
 proc toOpenArray*[T](x: openArray[T]; first, last: int): openArray[T] {.
   magic: "Slice".}
 proc toOpenArray*[I, T](x: array[I, T]; first, last: I): openArray[T] {.
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 9c7c83aab..3de6d8713 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -20,6 +20,37 @@ template track(op, address, size) =
 
 # We manage *chunks* of memory. Each chunk is a multiple of the page size.
 # Each chunk starts at an address that is divisible by the page size.
+# Small chunks may be divided into smaller cells of reusable pointers to reduce the number of page allocations.
+
+# An allocation of a small pointer looks approximately like this
+#[
+
+  alloc -> rawAlloc -> No free chunk available > Request a new page from tslf -> result = chunk.data -------------+
+              |                                                                                                   |
+              v                                                                                                   |
+    Free chunk available                                                                                          |
+              |                                                                                                   |
+              v                                                                                                   v
+      Fetch shared cells -> No free cells available -> Advance acc -> result = chunk.data + chunk.acc -------> return
+    (may not add new cells)                                                                                       ^
+              |                                                                                                   |
+              v                                                                                                   |
+     Free cells available -> result = chunk.freeList -> Advance chunk.freeList -----------------------------------+
+]#
+# so it is split into 3 paths, where the last path is preferred to prevent unnecessary allocations.
+#
+#
+# A deallocation of a small pointer then looks like this
+#[
+  dealloc -> rawDealloc -> chunk.owner == addr(a) --------------> This thread owns the chunk ------> The current chunk is active    -> Chunk is completely unused -----> Chunk references no foreign cells
+                                      |                                       |                   (Add cell into the current chunk)                 |                  Return the current chunk back to tlsf
+                                      |                                       |                                   |                                 |
+                                      v                                       v                                   v                                 v
+                      A different thread owns this chunk.     The current chunk is not active.          chunk.free was < size      Chunk references foreign cells, noop
+                      Add the cell to a.sharedFreeLists      Add the cell into the active chunk          Activate the chunk                       (end)
+                                    (end)                                    (end)                              (end)
+]#
+# So "true" deallocation is delayed for as long as possible in favor of reusing cells.
 
 const
   nimMinHeapPages {.intdefine.} = 128 # 0.5 MB
@@ -71,6 +102,8 @@ const
 
 type
   FreeCell {.final, pure.} = object
+    # A free cell is a pointer that has been freed, meaning it became available for reuse.
+    # It may become foreign if it is lent to a chunk that did not create it, doing so reduces the amount of needed pages.
     next: ptr FreeCell  # next free cell in chunk (overlaid with refcount)
     when not defined(gcDestructors):
       zeroField: int       # 0 means cell is not used (overlaid with typ field)
@@ -90,11 +123,18 @@ type
 
   SmallChunk = object of BaseChunk
     next, prev: PSmallChunk  # chunks of the same size
-    freeList: ptr FreeCell
-    free: int            # how many bytes remain
-    acc: int             # accumulator for small object allocation
-    when defined(gcDestructors):
-      sharedFreeList: ptr FreeCell # make no attempt at avoiding false sharing for now for this object field
+    freeList: ptr FreeCell   # Singly linked list of cells. They may be from foreign chunks or from the current chunk.
+                             #  Should be `nil` when the chunk isn't active in `a.freeSmallChunks`.
+    free: int32              # Bytes this chunk is able to provide using both the accumulator and free cells.
+                             # When a cell is considered foreign, its source chunk's free field is NOT adjusted until it
+                             #  reaches dealloc while the source chunk is active.
+                             # Instead, the receiving chunk gains the capacity and thus reserves space in the foreign chunk.
+    acc: uint32              # Offset from data, used when there are no free cells available but the chunk is considered free.
+    foreignCells: int        # When a free cell is given to a chunk that is not its origin,
+                             #  both the cell and the source chunk are considered foreign.
+                             # Receiving a foreign cell can happen both when deallocating from another thread or when
+                             #  the active chunk in `a.freeSmallChunks` is not the current chunk.
+                             # Freeing a chunk while `foreignCells > 0` leaks memory as all references to it become lost.
     data {.align: MemAlign.}: UncheckedArray[byte]      # start of usable memory
 
   BigChunk = object of BaseChunk # not necessarily > PageSize!
@@ -109,7 +149,12 @@ type
   MemRegion = object
     when not defined(gcDestructors):
       minLargeObj, maxLargeObj: int
-    freeSmallChunks: array[0..max(1,SmallChunkSize div MemAlign-1), PSmallChunk]
+    freeSmallChunks: array[0..max(1, SmallChunkSize div MemAlign-1), PSmallChunk]
+      # List of available chunks per size class. Only one is expected to be active per class.
+    when defined(gcDestructors):
+      sharedFreeLists: array[0..max(1, SmallChunkSize div MemAlign-1), ptr FreeCell]
+        # When a thread frees a pointer it did not create, it must not adjust the counters.
+        # Instead, the cell is placed here and deferred until the next allocation.
     flBitmap: uint32
     slBitmap: array[RealFli, uint32]
     matrix: array[RealFli, array[MaxSli, PBigChunk]]
@@ -433,7 +478,7 @@ iterator allObjects(m: var MemRegion): pointer {.inline.} =
 
           let size = c.size
           var a = cast[int](addr(c.data))
-          let limit = a + c.acc
+          let limit = a + c.acc.int
           while a <% limit:
             yield cast[pointer](a)
             a = a +% size
@@ -777,41 +822,42 @@ when defined(gcDestructors):
     sysAssert c.next == nil, "c.next pointer must be nil"
     atomicPrepend a.sharedFreeListBigChunks, c
 
-  proc addToSharedFreeList(c: PSmallChunk; f: ptr FreeCell) {.inline.} =
-    atomicPrepend c.sharedFreeList, f
+  proc addToSharedFreeList(c: PSmallChunk; f: ptr FreeCell; size: int) {.inline.} =
+    atomicPrepend c.owner.sharedFreeLists[size], f
+
+  const MaxSteps = 20
 
   proc compensateCounters(a: var MemRegion; c: PSmallChunk; size: int) =
     # rawDealloc did NOT do the usual:
     # `inc(c.free, size); dec(a.occ, size)` because it wasn't the owner of these
     # memory locations. We have to compensate here for these for the entire list.
-    # Well, not for the entire list, but for `max` elements of the list because
-    # we split the list in order to achieve bounded response times.
     var it = c.freeList
-    var x = 0
-    var maxIters = 20 # make it time-bounded
+    var total = 0
     while it != nil:
-      if maxIters == 0:
-        let rest = it.next.loada
-        if rest != nil:
-          it.next.storea nil
-          addToSharedFreeList(c, rest)
-        break
-      inc x, size
-      it = it.next.loada
-      dec maxIters
-    inc(c.free, x)
-    dec(a.occ, x)
+      inc total, size
+      let chunk = cast[PSmallChunk](pageAddr(it))
+      if c != chunk:
+        # The cell is foreign, potentially even from a foreign thread.
+        # It must block the current chunk from being freed, as doing so would leak memory.
+        inc c.foreignCells
+      it = it.next
+    # By not adjusting the foreign chunk we reserve space in it to prevent deallocation
+    inc(c.free, total)
+    dec(a.occ, total)
 
   proc freeDeferredObjects(a: var MemRegion; root: PBigChunk) =
     var it = root
-    var maxIters = 20 # make it time-bounded
+    var maxIters = MaxSteps # make it time-bounded
     while true:
+      let rest = it.next.loada
+      it.next.storea nil
+      deallocBigChunk(a, cast[PBigChunk](it))
       if maxIters == 0:
-        let rest = it.next.loada
-        it.next.storea nil
-        addToSharedFreeListBigChunks(a, rest)
+        if rest != nil:
+          addToSharedFreeListBigChunks(a, rest)
+          sysAssert a.sharedFreeListBigChunks != nil, "re-enqueing failed"
         break
-      it = it.next.loada
+      it = rest
       dec maxIters
       if it == nil: break
 
@@ -826,56 +872,85 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
   #c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
 
   if size <= SmallChunkSize-smallChunkOverhead():
+    template fetchSharedCells(tc: PSmallChunk) =
+      # Consumes cells from (potentially) foreign threads from `a.sharedFreeLists[s]`
+      when defined(gcDestructors):
+        if tc.freeList == nil:
+          when hasThreadSupport:
+            # Steal the entire list from `sharedFreeList`:
+            tc.freeList = atomicExchangeN(addr a.sharedFreeLists[s], nil, ATOMIC_RELAXED)
+          else:
+            tc.freeList = a.sharedFreeLists[s]
+            a.sharedFreeLists[s] = nil
+          # if `tc.freeList` isn't nil, `tc` will gain capacity.
+          # We must calculate how much it gained and how many foreign cells are included.
+          compensateCounters(a, tc, size)
+
     # allocate a small block: for small chunks, we use only its next pointer
     let s = size div MemAlign
     var c = a.freeSmallChunks[s]
     if c == nil:
+      # There is no free chunk of the requested size available, we need a new one.
       c = getSmallChunk(a)
+      # init all fields in case memory didn't get zeroed
       c.freeList = nil
+      c.foreignCells = 0
       sysAssert c.size == PageSize, "rawAlloc 3"
       c.size = size
-      c.acc = size
-      when defined(gcDestructors):
-        c.sharedFreeList = nil
-      c.free = SmallChunkSize - smallChunkOverhead() - size
+      c.acc = size.uint32
+      c.free = SmallChunkSize - smallChunkOverhead() - size.int32
       sysAssert c.owner == addr(a), "rawAlloc: No owner set!"
       c.next = nil
       c.prev = nil
-      listAdd(a.freeSmallChunks[s], c)
+      # Shared cells are fetched here in case `c.size * 2 >= SmallChunkSize - smallChunkOverhead()`.
+      # For those single cell chunks, we would otherwise have to allocate a new one almost every time.
+      fetchSharedCells(c)
+      if c.free >= size:
+        # Because removals from `a.freeSmallChunks[s]` only happen in the other alloc branch and during dealloc,
+        #  we must not add it to the list if it cannot be used the next time a pointer of `size` bytes is needed.
+        listAdd(a.freeSmallChunks[s], c)
       result = addr(c.data)
       sysAssert((cast[int](result) and (MemAlign-1)) == 0, "rawAlloc 4")
     else:
+      # There is a free chunk of the requested size available, use it.
       sysAssert(allocInv(a), "rawAlloc: begin c != nil")
       sysAssert c.next != c, "rawAlloc 5"
       #if c.size != size:
       #  c_fprintf(stdout, "csize: %lld; size %lld\n", c.size, size)
       sysAssert c.size == size, "rawAlloc 6"
-      when defined(gcDestructors):
-        if c.freeList == nil:
-          when hasThreadSupport:
-            c.freeList = atomicExchangeN(addr c.sharedFreeList, nil, ATOMIC_RELAXED)
-          else:
-            c.freeList = c.sharedFreeList
-            c.sharedFreeList = nil
-          compensateCounters(a, c, size)
       if c.freeList == nil:
-        sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize,
+        sysAssert(c.acc.int + smallChunkOverhead() + size <= SmallChunkSize,
                   "rawAlloc 7")
-        result = cast[pointer](cast[int](addr(c.data)) +% c.acc)
+        result = cast[pointer](cast[int](addr(c.data)) +% c.acc.int)
         inc(c.acc, size)
       else:
+        # There are free cells available, prefer them over the accumulator
         result = c.freeList
         when not defined(gcDestructors):
           sysAssert(c.freeList.zeroField == 0, "rawAlloc 8")
         c.freeList = c.freeList.next
+        if cast[PSmallChunk](pageAddr(result)) != c:
+          # This cell isn't a blocker for the current chunk's deallocation anymore
+          dec(c.foreignCells)
+        else:
+          sysAssert(c == cast[PSmallChunk](pageAddr(result)), "rawAlloc: Bad cell")
+      # Even if the cell we return is foreign, the local chunk's capacity decreases.
+      # The capacity was previously reserved in the source chunk (when it first got allocated),
+      #  then added into the current chunk during dealloc,
+      #  so the source chunk will not be freed or leak memory because of this.
       dec(c.free, size)
       sysAssert((cast[int](result) and (MemAlign-1)) == 0, "rawAlloc 9")
       sysAssert(allocInv(a), "rawAlloc: end c != nil")
-    sysAssert(allocInv(a), "rawAlloc: before c.free < size")
-    if c.free < size:
-      sysAssert(allocInv(a), "rawAlloc: before listRemove test")
-      listRemove(a.freeSmallChunks[s], c)
-      sysAssert(allocInv(a), "rawAlloc: end listRemove test")
+      # We fetch deferred cells *after* advancing `c.freeList`/`acc` to adjust `c.free`.
+      # If after the adjustment it turns out there's free cells available,
+      #  the chunk stays in `a.freeSmallChunks[s]` and the need for a new chunk is delayed.
+      fetchSharedCells(c)
+      sysAssert(allocInv(a), "rawAlloc: before c.free < size")
+      if c.free < size:
+        # Even after fetching shared cells the chunk has no usable memory left. It is no longer the active chunk
+        sysAssert(allocInv(a), "rawAlloc: before listRemove test")
+        listRemove(a.freeSmallChunks[s], c)
+        sysAssert(allocInv(a), "rawAlloc: end listRemove test")
     sysAssert(((cast[int](result) and PageMask) - smallChunkOverhead()) %%
                size == 0, "rawAlloc 21")
     sysAssert(allocInv(a), "rawAlloc: end small size")
@@ -907,7 +982,7 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
     trackSize(c.size)
   sysAssert(isAccessible(a, result), "rawAlloc 14")
   sysAssert(allocInv(a), "rawAlloc: end")
-  when logAlloc: cprintf("var pointer_%p = alloc(%ld)\n", result, requestedSize)
+  when logAlloc: cprintf("var pointer_%p = alloc(%ld) # %p\n", result, requestedSize, addr a)
 
 proc rawAlloc0(a: var MemRegion, requestedSize: int): pointer =
   result = rawAlloc(a, requestedSize)
@@ -923,7 +998,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
   if isSmallChunk(c):
     # `p` is within a small chunk:
     var c = cast[PSmallChunk](c)
-    var s = c.size
+    let s = c.size
     #       ^ We might access thread foreign storage here.
     # The other thread cannot possibly free this block as it's still alive.
     var f = cast[ptr FreeCell](p)
@@ -938,31 +1013,48 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
         #echo("setting to nil: ", $cast[int](addr(f.zeroField)))
         sysAssert(f.zeroField != 0, "rawDealloc 1")
         f.zeroField = 0
-      f.next = c.freeList
-      c.freeList = f
       when overwriteFree:
         # set to 0xff to check for usage after free bugs:
         nimSetMem(cast[pointer](cast[int](p) +% sizeof(FreeCell)), -1'i32,
                 s -% sizeof(FreeCell))
-      # check if it is not in the freeSmallChunks[s] list:
-      if c.free < s:
-        # add it to the freeSmallChunks[s] array:
-        listAdd(a.freeSmallChunks[s div MemAlign], c)
-        inc(c.free, s)
+      let activeChunk = a.freeSmallChunks[s div MemAlign]
+      if activeChunk != nil and c != activeChunk:
+        # This pointer is not part of the active chunk, lend it out
+        #  and do not adjust the current chunk (same logic as compensateCounters.)
+        # Put the cell into the active chunk,
+        #  may prevent a queue of available chunks from forming in a.freeSmallChunks[s div MemAlign].
+        #  This queue would otherwise waste memory in the form of free cells until we return to those chunks.
+        f.next = activeChunk.freeList
+        activeChunk.freeList = f # lend the cell
+        inc(activeChunk.free, s) # By not adjusting the current chunk's capacity it is prevented from being freed
+        inc(activeChunk.foreignCells) # The cell is now considered foreign from the perspective of the active chunk
       else:
-        inc(c.free, s)
-        if c.free == SmallChunkSize-smallChunkOverhead():
-          listRemove(a.freeSmallChunks[s div MemAlign], c)
-          c.size = SmallChunkSize
-          freeBigChunk(a, cast[PBigChunk](c))
+        f.next = c.freeList
+        c.freeList = f
+        if c.free < s:
+          # The chunk could not have been active as it didn't have enough space to give
+          listAdd(a.freeSmallChunks[s div MemAlign], c)
+          inc(c.free, s)
+        else:
+          inc(c.free, s)
+          # Free only if the entire chunk is unused and there are no borrowed cells.
+          # If the chunk were to be freed while it references foreign cells,
+          #  the foreign chunks will leak memory and can never be freed.
+          if c.free == SmallChunkSize-smallChunkOverhead() and c.foreignCells == 0:
+            listRemove(a.freeSmallChunks[s div MemAlign], c)
+            c.size = SmallChunkSize
+            freeBigChunk(a, cast[PBigChunk](c))
     else:
+      when logAlloc: cprintf("dealloc(pointer_%p) # SMALL FROM %p CALLER %p\n", p, c.owner, addr(a))
+
       when defined(gcDestructors):
-        addToSharedFreeList(c, f)
+        addToSharedFreeList(c, f, s div MemAlign)
     sysAssert(((cast[int](p) and PageMask) - smallChunkOverhead()) %%
                s == 0, "rawDealloc 2")
   else:
     # set to 0xff to check for usage after free bugs:
     when overwriteFree: nimSetMem(p, -1'i32, c.size -% bigChunkOverhead())
+    when logAlloc: cprintf("dealloc(pointer_%p) # BIG %p\n", p, c.owner)
     when defined(gcDestructors):
       if c.owner == addr(a):
         deallocBigChunk(a, cast[PBigChunk](c))
@@ -970,8 +1062,9 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
         addToSharedFreeListBigChunks(c.owner[], cast[PBigChunk](c))
     else:
       deallocBigChunk(a, cast[PBigChunk](c))
+
   sysAssert(allocInv(a), "rawDealloc: end")
-  when logAlloc: cprintf("dealloc(pointer_%p)\n", p)
+  #when logAlloc: cprintf("dealloc(pointer_%p)\n", p)
 
 when not defined(gcDestructors):
   proc isAllocatedPtr(a: MemRegion, p: pointer): bool =
@@ -982,7 +1075,7 @@ when not defined(gcDestructors):
           var c = cast[PSmallChunk](c)
           var offset = (cast[int](p) and (PageSize-1)) -%
                       smallChunkOverhead()
-          result = (c.acc >% offset) and (offset %% c.size == 0) and
+          result = (c.acc.int >% offset) and (offset %% c.size == 0) and
             (cast[ptr FreeCell](p).zeroField >% 1)
         else:
           var c = cast[PBigChunk](c)
@@ -1000,7 +1093,7 @@ when not defined(gcDestructors):
           var c = cast[PSmallChunk](c)
           var offset = (cast[int](p) and (PageSize-1)) -%
                       smallChunkOverhead()
-          if c.acc >% offset:
+          if c.acc.int >% offset:
             sysAssert(cast[int](addr(c.data)) +% offset ==
                       cast[int](p), "offset is not what you think it is")
             var d = cast[ptr FreeCell](cast[int](addr(c.data)) +%
diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim
index fa7ca784d..e229a0f4b 100644
--- a/lib/system/arithmetics.nim
+++ b/lib/system/arithmetics.nim
@@ -1,4 +1,4 @@
-proc succ*[T: Ordinal](x: T, y: int = 1): T {.magic: "Succ", noSideEffect.} =
+proc succ*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Succ", noSideEffect.} =
   ## Returns the `y`-th successor (default: 1) of the value `x`.
   ##
   ## If such a value does not exist, `OverflowDefect` is raised
@@ -7,7 +7,7 @@ proc succ*[T: Ordinal](x: T, y: int = 1): T {.magic: "Succ", noSideEffect.} =
     assert succ(5) == 6
     assert succ(5, 3) == 8
 
-proc pred*[T: Ordinal](x: T, y: int = 1): T {.magic: "Pred", noSideEffect.} =
+proc pred*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Pred", noSideEffect.} =
   ## Returns the `y`-th predecessor (default: 1) of the value `x`.
   ##
   ## If such a value does not exist, `OverflowDefect` is raised
@@ -16,7 +16,7 @@ proc pred*[T: Ordinal](x: T, y: int = 1): T {.magic: "Pred", noSideEffect.} =
     assert pred(5) == 4
     assert pred(5, 3) == 2
 
-proc inc*[T: Ordinal](x: var T, y: int = 1) {.magic: "Inc", noSideEffect.} =
+proc inc*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Inc", noSideEffect.} =
   ## Increments the ordinal `x` by `y`.
   ##
   ## If such a value does not exist, `OverflowDefect` is raised or a compile
@@ -28,7 +28,7 @@ proc inc*[T: Ordinal](x: var T, y: int = 1) {.magic: "Inc", noSideEffect.} =
     inc(i, 3)
     assert i == 6
 
-proc dec*[T: Ordinal](x: var T, y: int = 1) {.magic: "Dec", noSideEffect.} =
+proc dec*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Dec", noSideEffect.} =
   ## Decrements the ordinal `x` by `y`.
   ##
   ## If such a value does not exist, `OverflowDefect` is raised or a compile
diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim
index ce5e486f7..a8d78bb93 100644
--- a/lib/system/comparisons.nim
+++ b/lib/system/comparisons.nim
@@ -324,7 +324,7 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} =
         return true
     else:
       var sameObject = false
-      {.emit: """`sameObject` = `x` === `y`""".}
+      {.emit: """`sameObject` = `x` === `y`;""".}
       if sameObject: return true
 
   if x.len != y.len:
diff --git a/lib/system/compilation.nim b/lib/system/compilation.nim
index cda16fae5..cdb976ed5 100644
--- a/lib/system/compilation.nim
+++ b/lib/system/compilation.nim
@@ -6,7 +6,7 @@ const
     ##   ```
     # see also std/private/since
 
-  NimMinor* {.intdefine.}: int = 1
+  NimMinor* {.intdefine.}: int = 2
     ## is the minor number of Nim's version.
     ## Odd for devel, even for releases.
 
diff --git a/lib/system/hti.nim b/lib/system/hti.nim
index 9acaae88b..a26aff982 100644
--- a/lib/system/hti.nim
+++ b/lib/system/hti.nim
@@ -59,7 +59,7 @@ type
     tyOwned, tyUnused1, tyUnused2,
     tyVarargsHidden,
     tyUncheckedArray,
-    tyProxyHidden,
+    tyErrorHidden,
     tyBuiltInTypeClassHidden,
     tyUserTypeClassHidden,
     tyUserTypeClassInstHidden,
diff --git a/lib/system/indices.nim b/lib/system/indices.nim
index e1ac68383..f2bad2528 100644
--- a/lib/system/indices.nim
+++ b/lib/system/indices.nim
@@ -80,8 +80,6 @@ proc `[]`*[T, U: Ordinal](s: string, x: HSlice[T, U]): string {.inline, systemRa
   ##   var s = "abcdef"
   ##   assert s[1..3] == "bcd"
   ##   ```
-  # Workaround bug #22852
-  result = ""
   let a = s ^^ x.a
   let L = (s ^^ x.b) - a + 1
   result = newString(L)
@@ -112,13 +110,13 @@ proc `[]`*[Idx, T; U, V: Ordinal](a: array[Idx, T], x: HSlice[U, V]): seq[T] {.s
   ##   var a = [1, 2, 3, 4]
   ##   assert a[0..2] == @[1, 2, 3]
   ##   ```
+  ##
+  ## See also:
+  ## * `toOpenArray(array[I, T];I,I) <#toOpenArray,array[I,T],I,I>`_
   let xa = a ^^ x.a
   let L = (a ^^ x.b) - xa + 1
-  # Workaround bug #22852:
-  result = newSeq[T](if L < 0: 0 else: L)
+  result = newSeq[T](L)
   for i in 0..<L: result[i] = a[Idx(i + xa)]
-  # Workaround bug #22852
-  discard Natural(L)
 
 proc `[]=`*[Idx, T; U, V: Ordinal](a: var array[Idx, T], x: HSlice[U, V], b: openArray[T]) {.systemRaisesDefect.} =
   ## Slice assignment for arrays.
@@ -141,6 +139,9 @@ proc `[]`*[T; U, V: Ordinal](s: openArray[T], x: HSlice[U, V]): seq[T] {.systemR
   ##   var s = @[1, 2, 3, 4]
   ##   assert s[0..2] == @[1, 2, 3]
   ##   ```
+  ##
+  ## See also:
+  ## * `toOpenArray(openArray[T];int,int) <#toOpenArray,openArray[T],int,int>`_
   let a = s ^^ x.a
   let L = (s ^^ x.b) - a + 1
   newSeq(result, L)
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 9f9a410d5..5599240fd 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -622,37 +622,6 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef =
   else:
     result = src
 
-proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} =
-  {.emit: "`result` = null;".}
-  case ti.kind
-  of tyPtr, tyRef, tyVar, tyNil:
-    if isFatPointer(ti):
-      {.emit: """
-        `result` = [null, 0];
-      """.}
-  of tySet:
-    {.emit: """
-      `result` = {};
-    """.}
-  of tyTuple, tyObject:
-    if ti.kind == tyObject:
-      {.emit: "`result` = {m_type: `ti`};".}
-    else:
-      {.emit: "`result` = {};".}
-  of tySequence, tyOpenArray, tyString:
-    {.emit: """
-      `result` = [];
-    """.}
-  of tyArrayConstr, tyArray:
-    {.emit: """
-      `result` = new Array(`x`.length);
-      for (var i = 0; i < `x`.length; ++i) {
-        `result`[i] = genericReset(`x`[i], `ti`.base);
-      }
-    """.}
-  else:
-    discard
-
 proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {.
                 asmNoStackFrame, compilerproc.} =
   # types are fake
diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim
index bdf6145a1..cf81f6d86 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -253,11 +253,12 @@ proc cpDir*(`from`, to: string) {.raises: [OSError].} =
 proc exec*(command: string) {.
   raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} =
   ## Executes an external process. If the external process terminates with
-  ## a non-zero exit code, an OSError exception is raised.
+  ## a non-zero exit code, an OSError exception is raised. The command is
+  ## executed relative to the current source path.
   ##
-  ## **Note:** If you need a version of `exec` that returns the exit code
-  ## and text output of the command, you can use `system.gorgeEx
-  ## <system.html#gorgeEx,string,string,string>`_.
+  ## .. note:: If you need a version of `exec` that returns the exit code
+  ##   and text output of the command, you can use `system.gorgeEx
+  ##   <system.html#gorgeEx,string,string,string>`_.
   log "exec: " & command:
     if rawExec(command) != 0:
       raise newException(OSError, "FAILED: " & command)
@@ -267,11 +268,17 @@ proc exec*(command: string, input: string, cache = "") {.
   raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} =
   ## Executes an external process. If the external process terminates with
   ## a non-zero exit code, an OSError exception is raised.
+  ##
+  ## .. warning:: This version of `exec` is executed relative to the nimscript
+  ##   module path, which affects how the command resolves relative paths. Thus
+  ##   it is generally better to use `gorgeEx` directly when you need more
+  ##   control over the execution environment or when working with commands
+  ##   that deal with relative paths.
   log "exec: " & command:
     let (output, exitCode) = gorgeEx(command, input, cache)
+    echo output
     if exitCode != 0:
       raise newException(OSError, "FAILED: " & command)
-    echo output
 
 proc selfExec*(command: string) {.
   raises: [OSError], tags: [ExecIOEffect, WriteIOEffect].} =
diff --git a/lib/system/orc.nim b/lib/system/orc.nim
index 463c40c4d..c02a24989 100644
--- a/lib/system/orc.nim
+++ b/lib/system/orc.nim
@@ -146,7 +146,7 @@ proc unregisterCycle(s: Cell) =
   let idx = s.rootIdx-1
   when false:
     if idx >= roots.len or idx < 0:
-      cprintf("[Bug!] %ld\n", idx)
+      cprintf("[Bug!] %ld %ld\n", idx, roots.len)
       rawQuit 1
   roots.d[idx] = roots.d[roots.len-1]
   roots.d[idx][0].rootIdx = idx+1
@@ -303,6 +303,14 @@ proc collectColor(s: Cell; desc: PNimTypeV2; col: int; j: var GcEnv) =
         t.setColor(colBlack)
         trace(t, desc, j)
 
+const
+  defaultThreshold = when defined(nimFixedOrc): 10_000 else: 128
+
+when defined(nimStressOrc):
+  const rootsThreshold = 10 # broken with -d:nimStressOrc: 10 and for havlak iterations 1..8
+else:
+  var rootsThreshold {.threadvar.}: int
+
 proc collectCyclesBacon(j: var GcEnv; lowMark: int) =
   # pretty direct translation from
   # https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon01Concurrent.pdf
@@ -341,22 +349,25 @@ proc collectCyclesBacon(j: var GcEnv; lowMark: int) =
     s.rootIdx = 0
     collectColor(s, roots.d[i][1], colToCollect, j)
 
+  # Bug #22927: `free` calls destructors which can append to `roots`.
+  # We protect against this here by setting `roots.len` to 0 and also
+  # setting the threshold so high that no cycle collection can be triggered
+  # until we are out of this critical section:
+  when not defined(nimStressOrc):
+    let oldThreshold = rootsThreshold
+    rootsThreshold = high(int)
+  roots.len = 0
+
   for i in 0 ..< j.toFree.len:
     when orcLeakDetector:
       writeCell("CYCLIC OBJECT FREED", j.toFree.d[i][0], j.toFree.d[i][1])
     free(j.toFree.d[i][0], j.toFree.d[i][1])
 
+  when not defined(nimStressOrc):
+    rootsThreshold = oldThreshold
+
   inc j.freed, j.toFree.len
   deinit j.toFree
-  #roots.len = 0
-
-const
-  defaultThreshold = when defined(nimFixedOrc): 10_000 else: 128
-
-when defined(nimStressOrc):
-  const rootsThreshold = 10 # broken with -d:nimStressOrc: 10 and for havlak iterations 1..8
-else:
-  var rootsThreshold {.threadvar.}: int
 
 when defined(nimOrcStats):
   var freedCyclicObjects {.threadvar.}: int
@@ -396,7 +407,8 @@ proc collectCycles() =
     collectCyclesBacon(j, 0)
 
   deinit j.traceStack
-  deinit roots
+  if roots.len == 0:
+    deinit roots
 
   when not defined(nimStressOrc):
     # compute the threshold based on the previous history
diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim
index 30e84ebee..761d66aec 100644
--- a/lib/system/reprjs.nim
+++ b/lib/system/reprjs.nim
@@ -29,7 +29,7 @@ proc reprBool(x: bool): string {.compilerRtl.} =
 proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
   var tmp: bool
   let item = typ.node.sons[e]
-  {.emit: "`tmp` = `item` !== undefined".}
+  {.emit: "`tmp` = `item` !== undefined;".}
   if tmp:
     result = makeNimstrLit(item.name)
   else:
@@ -136,7 +136,7 @@ proc reprArray(a: pointer, typ: PNimType,
   add(result, "]")
 
 proc isPointedToNil(p: pointer): bool =
-  {. emit: "if (`p` === null) {`result` = true};\n" .}
+  {. emit: "if (`p` === null) {`result` = true;}\n" .}
 
 proc reprRef(result: var string, p: pointer, typ: PNimType,
           cl: var ReprClosure) =
diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim
index 8b3e9ee88..572e77408 100644
--- a/lib/system/seqs_v2.nim
+++ b/lib/system/seqs_v2.nim
@@ -90,6 +90,12 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin
       q.cap = newCap
       result = q
 
+proc zeroNewElements(len: int; q: pointer; addlen, elemSize, elemAlign: int) {.
+    noSideEffect, tags: [], raises: [], compilerRtl.} =
+  {.noSideEffect.}:
+    let headerSize = align(sizeof(NimSeqPayloadBase), elemAlign)
+    zeroMem(q +! headerSize +! len * elemSize, addlen * elemSize)
+
 proc prepareSeqAddUninit(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
     noSideEffect, tags: [], raises: [], compilerRtl.} =
   {.noSideEffect.}:
diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim
index dbee10777..404b4f78d 100644
--- a/lib/system/strs_v2.nim
+++ b/lib/system/strs_v2.nim
@@ -166,7 +166,7 @@ proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} =
   s.len = newLen
 
 proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
-  if a.p == b.p: return
+  if a.p == b.p and a.len == b.len: return
   if isLiteral(b):
     # we can shallow copy literals:
     frees(a)
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index e4d6479ec..3621c4960 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -220,7 +220,10 @@ proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} =
 proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
   let n = max(newLen, 0)
   if s == nil:
-    result = mnewString(n)
+    if n == 0:
+      return s
+    else:
+      result = mnewString(n)
   elif n <= s.space:
     result = s
   else:
@@ -301,7 +304,10 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
     compilerRtl.} =
   sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq"
   if s == nil:
-    result = cast[PGenericSeq](newSeq(typ, newLen))
+    if newLen == 0:
+      result = s
+    else:
+      result = cast[PGenericSeq](newSeq(typ, newLen))
   else:
     let elemSize = typ.base.size
     let elemAlign = typ.base.align
diff --git a/nimdoc/extlinks/project/expected/_._/util.html b/nimdoc/extlinks/project/expected/_._/util.html
index 2078d208c..32dab9216 100644
--- a/nimdoc/extlinks/project/expected/_._/util.html
+++ b/nimdoc/extlinks/project/expected/_._/util.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>nimdoc/extlinks/util</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -97,8 +101,5 @@
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/extlinks/project/expected/doc/manual.html b/nimdoc/extlinks/project/expected/doc/manual.html
index 64a0f7b7e..2946f803a 100644
--- a/nimdoc/extlinks/project/expected/doc/manual.html
+++ b/nimdoc/extlinks/project/expected/doc/manual.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Nothing User Manual</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -37,8 +41,5 @@
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/extlinks/project/expected/main.html b/nimdoc/extlinks/project/expected/main.html
index d86bd1d35..1e7c9c126 100644
--- a/nimdoc/extlinks/project/expected/main.html
+++ b/nimdoc/extlinks/project/expected/main.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>nimdoc/extlinks/project/main</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -134,8 +138,5 @@
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/extlinks/project/expected/sub/submodule.html b/nimdoc/extlinks/project/expected/sub/submodule.html
index 786de5b86..408ce2060 100644
--- a/nimdoc/extlinks/project/expected/sub/submodule.html
+++ b/nimdoc/extlinks/project/expected/sub/submodule.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>nimdoc/extlinks/project/sub/submodule</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -123,8 +127,5 @@
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/extlinks/project/expected/theindex.html b/nimdoc/extlinks/project/expected/theindex.html
index 86af18407..cf250edd1 100644
--- a/nimdoc/extlinks/project/expected/theindex.html
+++ b/nimdoc/extlinks/project/expected/theindex.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Index</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -51,8 +55,5 @@
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html
index 6bfc4bc79..a26704133 100644
--- a/nimdoc/rst2html/expected/rst_examples.html
+++ b/nimdoc/rst2html/expected/rst_examples.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Not a Nim Manual</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -266,8 +270,5 @@ stmt = IND{&gt;} stmt ^+ IND{=} DED  # list of statements
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/test_doctype/expected/test_doctype.html b/nimdoc/test_doctype/expected/test_doctype.html
index 149c88a18..2cbf6ec0f 100644
--- a/nimdoc/test_doctype/expected/test_doctype.html
+++ b/nimdoc/test_doctype/expected/test_doctype.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>nimdoc/test_doctype/test_doctype</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -58,8 +62,7 @@
     <div id="tocRoot"></div>
     
     <p class="module-desc"><p>Check</p>
-<p><pre class="listing">
-<span class="Identifier">text</span></pre></p>
+<p><pre class="listing"><span class="Identifier">text</span></pre></p>
 
 <h1><a class="toc-backref" id="check" href="#check">Check</a></h1>
 <h1><a class="toc-backref" id="text" href="#text">text</a></h1></p>
@@ -75,8 +78,5 @@
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html
index 80f09c5ad..4370f0df8 100644
--- a/nimdoc/test_out_index_dot_html/expected/index.html
+++ b/nimdoc/test_out_index_dot_html/expected/index.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>nimdoc/test_out_index_dot_html/foo</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -97,8 +101,5 @@
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/test_out_index_dot_html/expected/theindex.html b/nimdoc/test_out_index_dot_html/expected/theindex.html
index dcda2574c..ca7c2d7af 100644
--- a/nimdoc/test_out_index_dot_html/expected/theindex.html
+++ b/nimdoc/test_out_index_dot_html/expected/theindex.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Index</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -35,8 +39,5 @@
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css
index a9e4ac9c6..0c399e4c1 100644
--- a/nimdoc/testproject/expected/nimdoc.out.css
+++ b/nimdoc/testproject/expected/nimdoc.out.css
@@ -623,8 +623,8 @@ pre {
 

 table.line-nums-table {

   border-radius: 4px;

-  border: 1px solid #cccccc;

-  background-color: ghostwhite;

+  border: 1px solid var(--border);

+  background-color: var(--secondary-background);

   border-collapse: separate;

   margin-top: 15px;

   margin-bottom: 25px; }

@@ -660,6 +660,9 @@ table {
   border-collapse: collapse;

   border-color: var(--third-background);

   border-spacing: 0;

+}

+

+table:not(.line-nums-table) {

   font-size: 0.9em;

 }

 

@@ -678,7 +681,7 @@ table th.docinfo-name {
   text-align: right;

 }

 

-table tr:hover {

+table:not(.line-nums-table) tr:hover {

   background-color: var(--third-background); }

 

 

diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html
index 4ddf458f2..6decf79a3 100644
--- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html
+++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>subdir/subdir_b/utils</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -606,8 +610,5 @@ Ref. <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href=
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html
index cd2c71227..43a72d99d 100644
--- a/nimdoc/testproject/expected/testproject.html
+++ b/nimdoc/testproject/expected/testproject.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>testproject</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -1252,8 +1256,5 @@ bar
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html
index 6b811f5e2..71a487e0c 100644
--- a/nimdoc/testproject/expected/theindex.html
+++ b/nimdoc/testproject/expected/theindex.html
@@ -7,6 +7,10 @@
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Index</title>
 
+<!-- Google fonts -->
+<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
+<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
+
 <!-- Favicon -->
 <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
@@ -423,8 +427,5 @@
     </div>
   </div>
   
-  <!-- Google fonts -->
-  <link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
-  <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 </body>
 </html>
diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim
index 8e8c58597..e5abf0d2d 100644
--- a/nimpretty/nimpretty.nim
+++ b/nimpretty/nimpretty.nim
@@ -116,7 +116,13 @@ proc main =
   for kind, key, val in getopt():
     case kind
     of cmdArgument:
-      infiles.add(key.addFileExt(".nim"))
+      if dirExists(key):
+        for file in walkDirRec(key, skipSpecial = true):
+          if file.endsWith(".nim") or file.endsWith(".nimble"):
+            infiles.add(file)
+      else:
+        infiles.add(key.addFileExt(".nim"))
+
     of cmdLongOption, cmdShortOption:
       case normalize(key)
       of "help", "h": writeHelp()
diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim
index 67fc2f8c4..04bae08c1 100644
--- a/nimsuggest/nimsuggest.nim
+++ b/nimsuggest/nimsuggest.nim
@@ -134,7 +134,8 @@ const
   #List of currently supported capabilities. So lang servers/ides can iterate over and check for what's enabled
   Capabilities = [
     "con", #current NimSuggest supports the `con` commmand
-    "exceptionInlayHints"
+    "exceptionInlayHints",
+    "unknownFile", #current NimSuggest can handle unknown files
   ]
 
 proc parseQuoted(cmd: string; outp: var string; start: int): int =
@@ -230,6 +231,14 @@ proc clearInstCache(graph: ModuleGraph, projectFileIdx: FileIndex) =
   for id in procIdsToDelete:
     graph.procInstCache.del id
 
+  for tbl in mitems(graph.attachedOps):
+    var attachedOpsToDelete = newSeq[ItemId]()
+    for id in tbl.keys:
+      if id.module == projectFileIdx.int and sfOverridden in resolveAttachedOp(graph, tbl[id]).flags:
+        attachedOpsToDelete.add id
+    for id in attachedOpsToDelete:
+      tbl.del id
+
 proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int, tag: string,
              graph: ModuleGraph) =
   let conf = graph.config
@@ -758,20 +767,16 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
 
   if gMode != mstdin:
     conf.writelnHook = proc (msg: string) = discard
-  # 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""
-
+  conf.prefixDir = conf.getPrefixDir()
   #msgs.writelnHook = proc (line: string) = log(line)
   myLog("START " & conf.projectFull.string)
 
   var graph = newModuleGraph(cache, conf)
   if self.loadConfigsAndProcessCmdLine(cache, conf, graph):
+
+    if conf.selectedGC == gcUnselected and
+          conf.backend != backendJs:
+      initOrcDefines(conf)
     mainCommand(graph)
 
 # v3 start
@@ -1065,10 +1070,6 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
   var fileIndex: FileIndex
 
   if not (cmd in {ideRecompile, ideGlobalSymbols}):
-    if not fileInfoKnown(conf, file):
-      myLog fmt "{file} is unknown, returning no results"
-      return
-
     fileIndex = fileInfoIdx(conf, file)
     msgs.setDirtyFile(
       conf,
@@ -1344,13 +1345,7 @@ else:
       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""
+      conf.prefixDir = conf.getPrefixDir()
     else:
       conf.prefixDir = AbsoluteDir nimPath
 
diff --git a/nimsuggest/tests/tarrowcrash.nim b/nimsuggest/tests/tarrowcrash.nim
new file mode 100644
index 000000000..a303e88f5
--- /dev/null
+++ b/nimsuggest/tests/tarrowcrash.nim
@@ -0,0 +1,20 @@
+# issue #24179
+
+import sugar
+
+type
+    Parser[T] = object
+    
+proc eatWhile[T](p: Parser[T], predicate: T -> bool): seq[T] =
+    return @[]
+
+proc skipWs(p: Parser[char]) =
+    discard p.eatWhile((c: char) => c == 'a')
+#[!]#
+    
+discard """
+$nimsuggest --tester $file
+>chk $1
+chk;;skUnknown;;;;Hint;;???;;0;;-1;;">> (toplevel): import(dirty): tests/tarrowcrash.nim [Processing]";;0
+chk;;skUnknown;;;;Hint;;$file;;11;;5;;"\'skipWs\' is declared but not used [XDeclaredButNotUsed]";;0
+"""
diff --git a/nimsuggest/tests/tchk2.nim b/nimsuggest/tests/tchk2.nim
new file mode 100644
index 000000000..f5404368d
--- /dev/null
+++ b/nimsuggest/tests/tchk2.nim
@@ -0,0 +1,35 @@
+# bug #22794
+type O = object
+
+proc `=destroy`(x: O) = discard
+proc `=trace`(x: var O; env: pointer) = discard
+proc `=copy`(a: var O; b: O) = discard
+proc `=dup`(a: O): O {.nodestroy.} = a
+proc `=sink`(a: var O; b: O) = discard
+
+
+# bug #23316
+type SomeSturct = object
+
+proc `=destroy`(x: SomeSturct) =
+  echo "SomeSturct destroyed"
+
+# bug #23867
+type ObjStr = object
+  s: string
+
+let ostr = ObjStr() # <-- nimsuggest crashes
+discard ostr
+
+type ObjSeq = object
+  s: seq[int]
+
+let oseq = ObjSeq() # <-- nimsuggest crashes
+discard oseq
+
+#[!]#
+discard """
+$nimsuggest --tester $file
+>chk $1
+chk;;skUnknown;;;;Hint;;???;;0;;-1;;">> (toplevel): import(dirty): tests/tchk2.nim [Processing]";;0
+"""
diff --git a/nimsuggest/tests/tgeneric_highlight.nim b/nimsuggest/tests/tgeneric_highlight.nim
index f351ab705..c7291d08b 100644
--- a/nimsuggest/tests/tgeneric_highlight.nim
+++ b/nimsuggest/tests/tgeneric_highlight.nim
@@ -7,12 +7,7 @@ $nimsuggest --tester $file
 >highlight $1
 highlight;;skType;;1;;7;;3
 highlight;;skProc;;1;;0;;6
-highlight;;skProc;;1;;0;;6
-highlight;;skProc;;1;;0;;6
 highlight;;skType;;2;;14;;3
 highlight;;skProc;;2;;7;;6
-highlight;;skProc;;2;;7;;6
-highlight;;skProc;;2;;7;;6
-highlight;;skTemplate;;3;;0;;8
 highlight;;skType;;3;;9;;3
 """
diff --git a/testament/important_packages.nim b/testament/important_packages.nim
index b9f891dad..efec04b3c 100644
--- a/testament/important_packages.nim
+++ b/testament/important_packages.nim
@@ -58,15 +58,19 @@ pkg "cligen", "nim c --path:. -r cligen.nim"
 pkg "combparser", "nimble test --mm:orc"
 pkg "compactdict"
 pkg "comprehension", "nimble test", "https://github.com/alehander92/comprehension"
+pkg "constantine", "nimble make_lib"
 pkg "cowstrings"
 pkg "criterion", allowFailure = true # needs testing binary
 pkg "datamancer"
 pkg "dashing", "nim c tests/functional.nim"
 pkg "delaunay"
+pkg "dnsclient", allowFailure = true # super fragile
 pkg "docopt"
+pkg "dotenv"
 # when defined(linux): pkg "drchaos"
 pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl"
 pkg "elvis"
+pkg "faststreams"
 pkg "fidget"
 pkg "fragments", "nim c -r fragments/dsl.nim", allowFailure = true # pending https://github.com/nim-lang/packages/issues/2115 
 pkg "fusion"
@@ -79,10 +83,13 @@ pkg "gnuplot", "nim c gnuplot.nim"
   # pending https://github.com/nim-lang/Nim/issues/16509
 pkg "hts", "nim c -o:htss src/hts.nim"
 pkg "httpauth"
+pkg "httputils"
 pkg "illwill", "nimble examples"
 pkg "inim"
 pkg "itertools", "nim doc src/itertools.nim"
 pkg "iterutils"
+pkg "json_rpc"
+pkg "json_serialization"
 pkg "jstin"
 pkg "karax", "nim c -r tests/tester.nim"
 pkg "kdtree", "nimble test -d:nimLegacyRandomInitRand", "https://github.com/jblindsay/kdtree"
@@ -92,11 +99,10 @@ pkg "macroutils"
 pkg "manu"
 pkg "markdown"
 pkg "measuremancer", "nimble testDeps; nimble -y test"
-# when unchained is version 0.3.7 or higher, use `nimble testDeps;`
 pkg "memo"
 pkg "msgpack4nim", "nim c -r tests/test_spec.nim"
 pkg "nake", "nim c nakefile.nim"
-pkg "neo", "nim c -d:blas=openblas --mm:refc tests/all.nim", url = "https://github.com/nim-lang/neo"
+pkg "neo", "nim c -d:blas=openblas --mm:refc tests/all.nim"
 pkg "nesm", "nimble tests", "https://github.com/nim-lang/NESM", useHead = true, allowFailure = true
   # inactive, tests not adapted to #23096
 pkg "netty"
@@ -124,6 +130,7 @@ pkg "nimwc", "nim c nimwc.nim"
 pkg "nimx", "nim c test/main.nim", allowFailure = true
 pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter"
 pkg "norm", "testament r tests/common/tmodel.nim"
+pkg "normalize"
 pkg "npeg", "nimble testarc"
 pkg "numericalnim", "nimble nimCI"
 pkg "optionsutils"
@@ -134,9 +141,10 @@ pkg "pixie"
 pkg "plotly", "nim c examples/all.nim"
 pkg "pnm"
 pkg "polypbren"
+pkg "presto"
 pkg "prologue", "nimble tcompile"
-pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim"
-pkg "pylib"
+# remove fork after https://github.com/PMunch/combparser/pull/7 is merged:
+pkg "protobuf", "nimble install -y https://github.com/metagn/combparser@#HEAD; nim c -o:protobuff -r src/protobuf.nim"
 pkg "rbtree"
 pkg "react", "nimble example"
 pkg "regex", "nim c src/regex"
@@ -145,6 +153,7 @@ pkg "RollingHash", "nim c -r tests/test_cyclichash.nim"
 pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim"
 pkg "sdl1", "nim c -r src/sdl.nim"
 pkg "sdl2_nim", "nim c -r sdl2/sdl.nim"
+pkg "serialization"
 pkg "sigv4", "nim c --mm:arc -r sigv4.nim", "https://github.com/disruptek/sigv4"
 pkg "sim"
 pkg "smtp", "nimble compileExample"
@@ -163,18 +172,22 @@ pkg "templates"
 pkg "tensordsl", "nim c -r --mm:refc tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git"
 pkg "terminaltables", "nim c src/terminaltables.nim"
 pkg "termstyle", "nim c -r termstyle.nim"
+pkg "testutils"
 pkg "timeit"
 pkg "timezones"
 pkg "tiny_sqlite"
 pkg "unicodedb", "nim c -d:release -r tests/tests.nim"
 pkg "unicodeplus", "nim c -d:release -r tests/tests.nim"
 pkg "union", "nim c -r tests/treadme.nim", url = "https://github.com/alaviss/union"
+pkg "unittest2"
 pkg "unpack"
-pkg "weave", "nimble test_gc_arc", useHead = true
+pkg "weave", "nimble install -y cligen@#HEAD; nimble test_gc_arc", useHead = true
+pkg "websock"
 pkg "websocket", "nim c websocket.nim"
-pkg "winim", "nim c winim.nim"
+# pkg "winim", allowFailure = true
 pkg "with"
 pkg "ws", allowFailure = true
 pkg "yaml"
 pkg "zero_functional", "nim c -r test.nim"
 pkg "zippy"
+pkg "zxcvbn"
diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim
index 66afd62af..a490b17c8 100644
--- a/testament/lib/stdtest/testutils.nim
+++ b/testament/lib/stdtest/testutils.nim
@@ -66,6 +66,11 @@ template enableRemoteNetworking*: bool =
   ## a `nim` invocation (possibly via additional intermediate processes).
   getEnv("NIM_TESTAMENT_REMOTE_NETWORKING") == "1"
 
+template disableSSLTesting*: bool =
+  ## TODO: workaround for GitHub Action gcc 14 matrix; remove this
+  ## matrix and the flag after Azure agent supports ubuntu 24.04
+  getEnv("NIM_TESTAMENT_DISABLE_SSL") == "1"
+
 template whenRuntimeJs*(bodyIf, bodyElse) =
   ##[
   Behaves as `when defined(js) and not nimvm` (which isn't legal yet).
diff --git a/testament/testament.nim b/testament/testament.nim
index e0a200e29..1e892e636 100644
--- a/testament/testament.nim
+++ b/testament/testament.nim
@@ -10,9 +10,12 @@
 ## This program verifies Nim against the testcases.
 
 import
-  strutils, pegs, os, osproc, streams, json, std/exitprocs,
-  backend, parseopt, specs, htmlgen, browsers, terminal,
-  algorithm, times, azure, intsets, macros
+  std/[strutils, pegs, os, osproc, streams, json,
+    parseopt, browsers, terminal, exitprocs,
+    algorithm, times, intsets, macros]
+
+import backend, specs, azure, htmlgen
+
 from std/sugar import dup
 import compiler/nodejs
 import lib/stdtest/testutils
@@ -528,6 +531,23 @@ proc testSpecHelper(r: var TResults, test: var TTest, expected: TSpec,
                         "exitcode: " & $given.exitCode & "\n\nOutput:\n" &
                         given.nimout, reExitcodesDiffer)
 
+
+
+proc changeTarget(extraOptions: string; defaultTarget: TTarget): TTarget =
+  result = defaultTarget
+  var p = parseopt.initOptParser(extraOptions)
+
+  while true:
+    parseopt.next(p)
+    case p.kind
+    of cmdEnd: break
+    of cmdLongOption, cmdShortOption:
+      if p.key == "b" or p.key == "backend":
+        result = parseEnum[TTarget](p.val.normalize)
+        # chooses the last one
+    else:
+      discard
+
 proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions: string) =
   for target in expected.targets:
     inc(r.total)
@@ -540,6 +560,7 @@ proc targetHelper(r: var TResults, test: TTest, expected: TSpec, extraOptions: s
     else:
       let nimcache = nimcacheDir(test.name, test.options, target)
       var testClone = test
+      let target = changeTarget(extraOptions, target)
       testSpecHelper(r, testClone, expected, target, extraOptions, nimcache)
 
 proc testSpec(r: var TResults, test: TTest, targets: set[TTarget] = {}) =
diff --git a/tests/alloc/tmembug.nim b/tests/alloc/tmembug.nim
new file mode 100644
index 000000000..63b51ec5d
--- /dev/null
+++ b/tests/alloc/tmembug.nim
@@ -0,0 +1,54 @@
+discard """
+  joinable: false
+"""
+
+import std / [atomics, strutils, sequtils]
+
+type
+  BackendMessage* = object
+    field*: seq[int]
+
+var
+  chan1: Channel[BackendMessage]
+  chan2: Channel[BackendMessage]
+
+chan1.open()
+chan2.open()
+
+proc routeMessage*(msg: BackendMessage) =
+  discard chan2.trySend(msg)
+
+var
+  recv: Thread[void]
+  stopToken: Atomic[bool]
+
+proc recvMsg() =
+  while not stopToken.load(moRelaxed):
+    let resp = chan1.tryRecv()
+    if resp.dataAvailable:
+      routeMessage(resp.msg)
+      echo "child consumes ", formatSize getOccupiedMem()
+
+createThread[void](recv, recvMsg)
+
+const MESSAGE_COUNT = 100
+
+proc main() =
+  let msg: BackendMessage = BackendMessage(field: (0..500).toSeq())
+  for j in 0..0: #100:
+    echo "New iteration"
+
+    for _ in 1..MESSAGE_COUNT:
+      chan1.send(msg)
+    echo "After sending"
+
+    var counter = 0
+    while counter < MESSAGE_COUNT:
+      let resp = recv(chan2)
+      counter.inc
+    echo "After receiving ", formatSize getOccupiedMem()
+
+  stopToken.store true, moRelaxed
+  joinThreads(recv)
+
+main()
diff --git a/tests/alloc/tmembug2.nim b/tests/alloc/tmembug2.nim
new file mode 100644
index 000000000..01bce6f14
--- /dev/null
+++ b/tests/alloc/tmembug2.nim
@@ -0,0 +1,58 @@
+discard """
+  disabled: "true"
+"""
+
+import std / [atomics, strutils, sequtils, isolation]
+
+import threading / channels
+
+type
+  BackendMessage* = object
+    field*: seq[int]
+
+const MESSAGE_COUNT = 100
+
+var
+  chan1 = newChan[BackendMessage](MESSAGE_COUNT*2)
+  chan2 = newChan[BackendMessage](MESSAGE_COUNT*2)
+
+#chan1.open()
+#chan2.open()
+
+proc routeMessage*(msg: BackendMessage) =
+  var m = isolate(msg)
+  discard chan2.trySend(m)
+
+var
+  thr: Thread[void]
+  stopToken: Atomic[bool]
+
+proc recvMsg() =
+  while not stopToken.load(moRelaxed):
+    var resp: BackendMessage
+    if chan1.tryRecv(resp):
+      #if resp.dataAvailable:
+      routeMessage(resp)
+      echo "child consumes ", formatSize getOccupiedMem()
+
+createThread[void](thr, recvMsg)
+
+proc main() =
+  let msg: BackendMessage = BackendMessage(field: (0..5).toSeq())
+  for j in 0..100:
+    echo "New iteration"
+
+    for _ in 1..MESSAGE_COUNT:
+      chan1.send(msg)
+    echo "After sending"
+
+    var counter = 0
+    while counter < MESSAGE_COUNT:
+      let resp = recv(chan2)
+      counter.inc
+    echo "After receiving ", formatSize getOccupiedMem()
+
+  stopToken.store true, moRelaxed
+  joinThreads(thr)
+
+main()
diff --git a/tests/arc/tarc_orc.nim b/tests/arc/tarc_orc.nim
index 594950d71..f2c7de2fc 100644
--- a/tests/arc/tarc_orc.nim
+++ b/tests/arc/tarc_orc.nim
@@ -136,4 +136,51 @@ proc main2 =
     doAssert a.len == 2
     doAssert b.len == 0
 
-main2()
\ No newline at end of file
+main2()
+
+block:
+  type
+    TestObj = object of RootObj
+      name: string
+    
+    TestSubObj = object of TestObj
+      objname: string
+
+  proc `=destroy`(x: TestObj) =
+    `=destroy`(x.name)
+
+  proc `=destroy`(x: TestSubObj) =
+    `=destroy`(x.objname)
+    `=destroy`(TestObj(x))
+
+  proc testCase() =
+    let t1 {.used.} = TestSubObj(objname: "tso1", name: "to1")
+
+  proc main() =
+    testCase()
+
+  main()
+
+block: # bug #23858
+  type Object = object
+    a: int
+    b: ref int
+  var x = 0
+  proc fn(): auto {.cdecl.} =
+    inc x
+    return Object()
+  discard fn()
+  doAssert x == 1
+
+block: # bug #24147
+  type
+    O = object of RootObj
+      val: string
+    OO = object of O
+
+  proc `=copy`(dest: var O, src: O) =
+      dest.val = src.val
+
+  let oo = OO(val: "hello world")
+  var ooCopy : OO
+  `=copy`(ooCopy, oo)
diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim
index 2570e410f..b4476ef4f 100644
--- a/tests/arc/tarcmisc.nim
+++ b/tests/arc/tarcmisc.nim
@@ -1,5 +1,6 @@
 discard """
   output: '''
+Destructor for TestTestObj
 =destroy called
 123xyzabc
 destroyed: false
@@ -31,14 +32,39 @@ true
 copying
 123
 42
+@["", "d", ""]
 ok
 destroying variable: 20
 destroying variable: 10
 closed
 '''
-  cmd: "nim c --gc:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file"
+  cmd: "nim c --mm:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file"
 """
 
+block: # bug #23627
+  type
+    TestObj = object of RootObj
+
+    Test2 = object of RootObj
+      foo: TestObj
+
+    TestTestObj = object of RootObj
+      shit: TestObj
+
+  proc `=destroy`(x: TestTestObj) =
+    echo "Destructor for TestTestObj"
+    let test = Test2(foo: TestObj())
+
+  proc testCaseT() =
+    let tt1 {.used.} = TestTestObj(shit: TestObj())
+
+
+  proc main() =
+    testCaseT()
+
+  main()
+
+
 # bug #9401
 
 type
@@ -46,13 +72,12 @@ type
     len: int
     data: ptr UncheckedArray[float]
 
-proc `=destroy`*(m: var MyObj) =
+proc `=destroy`*(m: MyObj) =
 
   echo "=destroy called"
 
   if m.data != nil:
     deallocShared(m.data)
-    m.data = nil
 
 type
   MyObjDistinct = distinct MyObj
@@ -104,7 +129,7 @@ bbb("123")
 type Variable = ref object
   value: int
 
-proc `=destroy`(self: var typeof(Variable()[])) =
+proc `=destroy`(self: typeof(Variable()[])) =
   echo "destroying variable: ",self.value
 
 proc newVariable(value: int): Variable =
@@ -158,7 +183,7 @@ type
   B = ref object of A
     x: int
 
-proc `=destroy`(x: var AObj) =
+proc `=destroy`(x: AObj) =
   close(x.io)
   echo "closed"
 
@@ -727,3 +752,85 @@ block: # bug #23505
 
   discard init(C)
 
+block: # bug #23524
+  type MyType = object
+    a: int
+
+  proc `=destroy`(typ: MyType) = discard
+
+  var t1 = MyType(a: 100)
+  var t2 = t1 # Should be a copy?
+
+  proc main() =
+    t2 = t1
+    doAssert t1.a == 100
+    doAssert t2.a == 100
+
+  main()
+
+block: # bug #23907
+  type
+    Thingy = object
+      value: int
+
+    ExecProc[C] = proc(value: sink C): int {.nimcall.}
+
+  proc `=copy`(a: var Thingy, b: Thingy) {.error.}
+
+  var thingyDestroyCount = 0
+
+  proc `=destroy`(thingy: Thingy) =
+    assert(thingyDestroyCount <= 0)
+    thingyDestroyCount += 1
+
+  proc store(value: sink Thingy): int =
+    result = value.value
+
+  let callback: ExecProc[Thingy] = store
+
+  doAssert callback(Thingy(value: 123)) == 123
+
+import std/strutils
+
+block: # bug #23974
+  func g(e: seq[string]): lent seq[string] = result = e
+  proc k(f: string): seq[string] = f.split("/")
+  proc n() =
+    const r = "/d/"
+    let t =
+      if true:
+        k(r).g()
+      else:
+        k("/" & r).g()
+    echo t
+
+  n()
+
+block: # bug #23973
+  func g(e: seq[string]): lent seq[string] = result = e
+  proc k(f: string): seq[string] = f.split("/")
+  proc n() =
+    const r = "/test/empty"  # or "/test/empty/1"
+    let a = k(r).g()
+    let t =
+      if true:
+        k(r).g()
+      else:
+        k("/" & r).g()   # or raiseAssert ""
+    doAssert t == a
+
+  n()
+
+block: # bug #24141
+  func reverse(s: var openArray[char]) =
+    s[0] = 'f'
+
+  func rev(s: var string) =
+    s.reverse
+
+  proc main =
+    var abc = "abc"
+    abc.rev
+    doAssert abc == "fbc"
+
+  main()
diff --git a/tests/arc/tcaseobj.nim b/tests/arc/tcaseobj.nim
index be1d722ed..3499f5c1e 100644
--- a/tests/arc/tcaseobj.nim
+++ b/tests/arc/tcaseobj.nim
@@ -338,3 +338,29 @@ block:
       doAssert ff.s == 12
 
     mainSync()
+
+import std/sequtils
+
+# bug #23690
+type
+  SomeObj* = object of RootObj
+
+  Item* = object
+    case kind*: 0..1
+    of 0:
+      a*: int
+      b*: SomeObj
+    of 1:
+      c*: string
+
+  ItemExt* = object
+    a*: Item
+    b*: string
+
+proc do1(x: int): seq[(string, Item)] =
+  result = @[("zero", Item(kind: 1, c: "first"))]
+
+proc do2(x: int, e: ItemExt): seq[(string, ItemExt)] =
+  do1(x).map(proc(v: (string, Item)): auto = (v[0], ItemExt(a: v[1], b: e.b)))
+
+doAssert $do2(0, ItemExt(a: Item(kind: 1, c: "second"), b: "third")) == """@[("zero", (a: (kind: 1, c: "first"), b: "third"))]"""
diff --git a/tests/arc/titeration_doesnt_copy.nim b/tests/arc/titeration_doesnt_copy.nim
index e1cdb6166..e510a6eff 100644
--- a/tests/arc/titeration_doesnt_copy.nim
+++ b/tests/arc/titeration_doesnt_copy.nim
@@ -54,3 +54,14 @@ proc toBinString*(data: openArray[uint8], col: int): string =
 
 doAssert @[0b0000_1111'u8, 0b1010_1010].toBinString(8) == "0000111110101010"
 doAssert @[0b1000_0000'u8, 0b0000_0000].toBinString(1) == "10"
+
+block: # bug #23982
+  iterator `..`(a, b: ptr int16): ptr int16 = discard
+  var a: seq[int16] #; let p = a[0].addr
+  var b: seq[ptr int16]
+
+  try:
+    for x in a[0].addr .. b[1]: # `p .. b[1]` works
+      discard
+  except IndexDefect:
+    discard
diff --git a/tests/arc/topenarray.nim b/tests/arc/topenarray.nim
index 67c512e4f..ba91666ba 100644
--- a/tests/arc/topenarray.nim
+++ b/tests/arc/topenarray.nim
@@ -68,3 +68,19 @@ block:
   doAssert foo(noBugConst) == expected
   let noBugSeq = @["0", "c", "a"]
   doAssert foo(noBugSeq) == expected
+
+block: # bug #20865
+  var p: pointer
+  var x: array[0, int]
+  # echo toOpenArray(x, 0, 1)[0] # Raises IndexDefect
+  doAssertRaises(IndexDefect):
+    echo toOpenArray(cast[ptr array[0, int]](p)[], 0, 1)[0] # Does not raise IndexDefect
+
+block: # bug #20987
+  var v: array[1, byte]
+
+  var p = cast[ptr array[0, byte]](addr v)
+
+  doAssertRaises(IndexDefect):
+    echo toOpenArray(p[], 1, 2)
+
diff --git a/tests/arc/tstringliteral.nim b/tests/arc/tstringliteral.nim
new file mode 100644
index 000000000..c5fac22d8
--- /dev/null
+++ b/tests/arc/tstringliteral.nim
@@ -0,0 +1,17 @@
+discard """
+  matrix: "--mm:arc; --mm:orc"
+"""
+
+block: # issue #24080
+  var a = (s: "a")
+  var b = "a"
+  a.s.setLen 0
+  b = a.s
+  doAssert b == ""
+
+block: # issue #24080, longer string
+  var a = (s: "abc")
+  var b = "abc"
+  a.s.setLen 2
+  b = a.s
+  doAssert b == "ab"
diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim
index 77d03f8f6..f53767408 100644
--- a/tests/async/tioselectors.nim
+++ b/tests/async/tioselectors.nim
@@ -58,7 +58,11 @@ when not defined(windows):
     registerHandle(selector, client_socket, {Event.Write}, 0)
 
     freeAddrInfo(aiList)
-    discard selector.select(100)
+
+    # make sure both sockets are selected
+    var nevs = 0
+    while nevs < 2:
+      nevs += selector.select(100).len
 
     var sockAddress: SockAddr
     var addrLen = sizeof(sockAddress).Socklen
@@ -427,6 +431,20 @@ when not defined(windows):
       doAssert(res[0].fd == dirfd and
                {Event.Vnode, Event.VnodeDelete} <= res[0].events)
 
+  proc pipe_test(): bool =
+    # closing the read end of a pipe will result in it automatically
+    # being removed from the kqueue; make sure no exception is raised
+    var s = newSelector[int]()
+    var fds: array[2, cint]
+    discard pipe(fds)
+    s.registerHandle(fds[1], {Write}, 0)
+    discard close(fds[0])
+    let res = s.select(-1)
+    doAssert(res.len == 1)
+    s.unregister(fds[1])
+    discard close(fds[1])
+    return true
+
   when hasThreadSupport:
 
     var counter = 0
@@ -468,6 +486,7 @@ when not defined(windows):
   when defined(macosx) or defined(freebsd) or defined(openbsd) or
        defined(netbsd):
     processTest("File notification test...", vnode_test())
+    processTest("Pipe test...", pipe_test())
   echo("All tests passed!")
 else:
   import nativesockets, winlean, os, osproc
diff --git a/tests/c/temit.nim b/tests/c/temit.nim
index ee7455d4c..1943c94ea 100644
--- a/tests/c/temit.nim
+++ b/tests/c/temit.nim
@@ -4,6 +4,7 @@ discard """
 # Test the new ``emit`` pragma:
 
 {.emit: """
+#include <stdio.h>
 static int cvariable = 420;
 
 """.}
diff --git a/tests/casestmt/tcase_issues.nim b/tests/casestmt/tcase_issues.nim
new file mode 100644
index 000000000..20a79df2c
--- /dev/null
+++ b/tests/casestmt/tcase_issues.nim
@@ -0,0 +1,7 @@
+discard """
+  targets: "c js"
+"""
+
+block: # bug #24031
+  case 0
+  else: discard
\ No newline at end of file
diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim
index aea0c96a4..66de4183d 100644
--- a/tests/casestmt/tcasestmt.nim
+++ b/tests/casestmt/tcasestmt.nim
@@ -41,6 +41,11 @@ block t8333:
   case 0
   of 'a': echo 0
   else: echo 1
+block: # issue #11422
+  var c: int = 5
+  case c
+  of 'a' .. 'c': discard
+  else: discard
 
 
 block emptyset_when:
diff --git a/tests/casestmt/trangeexhaustiveness.nim b/tests/casestmt/trangeexhaustiveness.nim
new file mode 100644
index 000000000..2b7f3558e
--- /dev/null
+++ b/tests/casestmt/trangeexhaustiveness.nim
@@ -0,0 +1,7 @@
+block: # issue #22661
+  template foo(a: typed) =
+    a
+    
+  foo:
+    case false
+    of false..true: discard
diff --git a/tests/ccgbugs/t10964.nim b/tests/ccgbugs/t10964.nim
index a331b16cd..c19db6997 100644
--- a/tests/ccgbugs/t10964.nim
+++ b/tests/ccgbugs/t10964.nim
@@ -3,4 +3,5 @@ func test*(input: var openArray[int32], start: int = 0, fin: int = input.len - 1
 

 var someSeq = @[1'i32]

 

-test(someSeq)
\ No newline at end of file
+test(someSeq)

+# bug with gcc 14
\ No newline at end of file
diff --git a/tests/ccgbugs/t13062.nim b/tests/ccgbugs/t13062.nim
index a8d2c1fec..cfda1da7c 100644
--- a/tests/ccgbugs/t13062.nim
+++ b/tests/ccgbugs/t13062.nim
@@ -24,7 +24,10 @@ type
     fulfilled: Atomic[bool]
 
 var x: Pledge
-when defined(gcRefc):
+when defined(cpp):
+  # TODO: fixme
+  discard "it doesn't work for refc/orc because of contrived `Atomic` in cpp"
+elif defined(gcRefc):
   doAssert x.repr == "[p = nil]"
-elif not defined(cpp): # fixme # bug #20081
+else: # fixme # bug #20081
   doAssert x.repr == "Pledge(p: nil)"
diff --git a/tests/ccgbugs/t20141.nim b/tests/ccgbugs/t20141.nim
index 499cd21aa..60e130690 100644
--- a/tests/ccgbugs/t20141.nim
+++ b/tests/ccgbugs/t20141.nim
@@ -16,7 +16,7 @@ template n[T, U](x: U): T =
 
 proc k() =
   var res: A
-  m(n[B](res))
+  m(n[B, A](res))
 
 proc w(mounter: U) = discard
 
@@ -24,4 +24,4 @@ proc mount(proto: U) = discard
 proc v() = mount k
 
 # This is required for failure
-w(v)
\ No newline at end of file
+w(v)
diff --git a/tests/ccgbugs/t23796.nim b/tests/ccgbugs/t23796.nim
new file mode 100644
index 000000000..421ec04d8
--- /dev/null
+++ b/tests/ccgbugs/t23796.nim
@@ -0,0 +1,25 @@
+discard """
+    targets: "c cpp"
+"""
+
+# bug #23796
+
+{.emit: """
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void fooArr(float data[3]) {}
+void fooIntArr(int id, float data[3]) {}
+
+#ifdef __cplusplus
+}
+#endif
+""".}
+
+proc fooArr(data: var array[3, cfloat]) {.importc.}
+proc fooIntArr(id: cint, data: var array[3, cfloat]) {.importc, nodecl.}
+
+var arr = [cfloat 1, 2, 3]
+fooArr(arr)
+fooIntArr(1, arr)
diff --git a/tests/ccgbugs/tcgbug.nim b/tests/ccgbugs/tcgbug.nim
index 871d6b59c..2eddc6fdd 100644
--- a/tests/ccgbugs/tcgbug.nim
+++ b/tests/ccgbugs/tcgbug.nim
@@ -4,6 +4,7 @@ success
 M1 M2
 ok
 '''
+matrix: "--mm:refc;--mm:orc"
 """
 
 type
@@ -133,3 +134,30 @@ proc foo = # bug #23280
   doAssert L mod 6 == 0 
 
 foo()
+
+block: # bug #9940
+  {.emit:"""/*TYPESECTION*/
+typedef struct { int base; } S;
+""".}
+
+  type S {.importc: "S", completeStruct.} = object
+    base: cint
+  proc init(x:ptr S) =
+    x.base = 1
+
+  type
+    Foo = object
+      a: seq[float]
+      b: seq[float]
+      c: seq[float]
+      d: seq[float]
+      s: S
+
+  proc newT(): Foo =
+    var t: Foo
+    t.s.addr.init
+    doAssert t.s.base == 1
+    t
+
+  var t = newT()
+  doAssert t.s.base == 1
diff --git a/tests/ccgbugs/tsamename3.nim b/tests/ccgbugs/tsamename3.nim
index a69391e5c..ded18e9f8 100644
--- a/tests/ccgbugs/tsamename3.nim
+++ b/tests/ccgbugs/tsamename3.nim
@@ -109,3 +109,12 @@ block: # make sure `hashType` doesn't recurse infinitely
       a, b: PFoo
       c: int
   var a: PFoo
+
+block: # issue #22571
+  macro foo(x: typed) =
+    result = x
+
+  block: # or `proc main =`
+    foo:
+      type Foo = object
+    doAssert $Foo() == "()"
diff --git a/tests/closure/t8550.nim b/tests/closure/t8550.nim
index 153246f08..a07f45cdc 100644
--- a/tests/closure/t8550.nim
+++ b/tests/closure/t8550.nim
@@ -1,4 +1,5 @@
 discard """
+  targets: "c js"
   output: "@[\"42\"]"
 """
 
diff --git a/tests/closure/tnested.nim b/tests/closure/tnested.nim
index 31963ea86..ec5af9b13 100644
--- a/tests/closure/tnested.nim
+++ b/tests/closure/tnested.nim
@@ -1,4 +1,5 @@
 discard """
+targets: "c js"
 output: '''
 foo88
 23 24foo 88
@@ -183,14 +184,32 @@ block tclosure2:
 
 import typetraits
 
-proc myDiscard[T](a: T) = discard
+block:
+  proc myDiscard[T](a: T) = discard
 
-proc foo() =
-  let a = 5
-  let f = (proc() =
-             myDiscard (proc() = echo a)
-          )
-  echo name(typeof(f))
+  proc foo() =
+    let a = 5
+    let f = (proc() =
+              myDiscard (proc() = echo a)
+            )
+    echo name(typeof(f))
 
-foo()
+  foo()
 
+
+block:
+  iterator foo: int {.closure.} =
+    yield 1
+    yield 2
+    yield 3
+
+  proc pork =
+    let call = foo
+    for i in call():
+      discard i
+
+    let call2 = foo
+    while not finished(call2):
+      discard call2()
+
+  pork()
diff --git a/tests/codegen/titaniummangle.nim b/tests/codegen/titaniummangle.nim
index 5ab4e3410..4b45e59ae 100644
--- a/tests/codegen/titaniummangle.nim
+++ b/tests/codegen/titaniummangle.nim
@@ -5,11 +5,11 @@ discard """
   ccodecheck: "'_ZN14titaniummangle8testFuncE6stringN14titaniummangle3FooE'"
   ccodecheck: "'_ZN14titaniummangle8testFuncE3int7varargsI6stringE'"
   ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle3BooE'"
-  ccodecheck: "'_ZN8testFunc8testFuncE8typeDescIN14titaniummangle17EnumAnotherSampleEE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE8typeDescIN14titaniummangle17EnumAnotherSampleEE'"
   ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI14uncheckedArrayI3intEE'"
   ccodecheck: "'_ZN14titaniummangle8testFuncE3setIN14titaniummangle10EnumSampleEE'"
   ccodecheck: "'_ZN14titaniummangle8testFuncE4procI6string6stringE'"
-  ccodecheck: "'_ZN8testFunc8testFuncE3intN10Comparable10ComparableE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3intN10Comparable10ComparableE'"
   ccodecheck: "'_ZN14titaniummangle8testFuncE3int3int'"
   ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle10EnumSampleE'"
   ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle17EnumAnotherSampleE'"
@@ -37,7 +37,6 @@ type
   Comparable = concept x, y
     (x < y) is bool
 
-type 
   Foo = object
     a: int32
     b: int32
@@ -45,8 +44,10 @@ type
   FooTuple = tuple
     a: int
     b: int
+
   Container[T] = object
-    data: T  
+    data: T
+      
   Container2[T, T2] = object
     data: T
     data2: T2
diff --git a/tests/compileoption/texperimental.nim b/tests/compileoption/texperimental.nim
new file mode 100644
index 000000000..be637e58a
--- /dev/null
+++ b/tests/compileoption/texperimental.nim
@@ -0,0 +1,20 @@
+static:
+  doAssert compileOption("experimental", "dotOperators")
+  doAssert compileOption("experimental", "callOperator")
+  doAssert compileOption("experimental", "parallel")
+  doAssert compileOption("experimental", "destructor")
+  doAssert compileOption("experimental", "notnil")
+  doAssert compileOption("experimental", "dynamicBindSym")
+  doAssert compileOption("experimental", "codeReordering")
+  doAssert compileOption("experimental", "compiletimeFFI")
+  doAssert compileOption("experimental", "vmopsDanger")
+  doAssert compileOption("experimental", "strictFuncs")
+  doAssert compileOption("experimental", "views")
+  doAssert compileOption("experimental", "strictNotNil")
+  doAssert compileOption("experimental", "strictEffects")
+  doAssert compileOption("experimental", "flexibleOptionalParams")
+  doAssert compileOption("experimental", "strictDefs")
+  doAssert compileOption("experimental", "strictCaseObjects")
+  doAssert compileOption("experimental", "inferGenericTypes")
+  doAssert compileOption("experimental", "openSym")
+  doAssert compileOption("experimental", "vtables")
diff --git a/tests/compileoption/texperimental.nims b/tests/compileoption/texperimental.nims
new file mode 100644
index 000000000..c2c357caa
--- /dev/null
+++ b/tests/compileoption/texperimental.nims
@@ -0,0 +1,19 @@
+switch("experimental", "dotOperators")
+switch("experimental", "callOperator")
+switch("experimental", "parallel")
+switch("experimental", "destructor")
+switch("experimental", "notnil")
+switch("experimental", "dynamicBindSym")
+switch("experimental", "codeReordering")
+switch("experimental", "compiletimeFFI")
+switch("experimental", "vmopsDanger")
+switch("experimental", "strictFuncs")
+switch("experimental", "views")
+switch("experimental", "strictNotNil")
+switch("experimental", "strictEffects")
+switch("experimental", "flexibleOptionalParams")
+switch("experimental", "strictDefs")
+switch("experimental", "strictCaseObjects")
+switch("experimental", "inferGenericTypes")
+switch("experimental", "openSym")
+switch("experimental", "vtables")
diff --git a/tests/concepts/tusertypeclasses2.nim b/tests/concepts/tusertypeclasses2.nim
index 0f5c737e8..6132bc2d8 100644
--- a/tests/concepts/tusertypeclasses2.nim
+++ b/tests/concepts/tusertypeclasses2.nim
@@ -48,8 +48,16 @@ block:
   foo4(x)
 
 block: # bug #9550
-  type Foo = concept c
-    for v in c: (v is char)
+  block:
+    type Foo = concept c
+      for v in c: (v is char)
 
-  func foo(c: Foo) = (for v in c: discard)
-  foo @['a', 'b' ,'c']
+    func foo(c: Foo) = (for v in c: discard)
+    foo @['a', 'b' ,'c']
+
+  block:
+    type Foo = concept c
+      for v in c: (v is char)
+
+    func foo(c: Foo) = (for v in c: discard)
+    foo ['a', 'b' ,'c']
diff --git a/tests/config.nims b/tests/config.nims
index 690123c4a..0b2b66d81 100644
--- a/tests/config.nims
+++ b/tests/config.nims
@@ -43,5 +43,7 @@ switch("define", "nimPreviewRangeDefault")
 switch("define", "nimPreviewNonVarDestructor")
 
 switch("warningAserror", "UnnamedBreak")
-switch("legacy", "verboseTypeMismatch")
+when not defined(testsConciseTypeMismatch):
+  switch("legacy", "verboseTypeMismatch")
 switch("experimental", "vtables")
+switch("experimental", "openSym")
diff --git a/tests/controlflow/tunreachable2.nim b/tests/controlflow/tunreachable2.nim
new file mode 100644
index 000000000..a658880f0
--- /dev/null
+++ b/tests/controlflow/tunreachable2.nim
@@ -0,0 +1,12 @@
+discard """
+  matrix: "--warningAsError:UnreachableCode"
+"""
+
+proc test(): bool =
+  block okay:
+    if true: break okay
+    return false
+
+  return true # Line 7 is here
+
+doAssert test()
diff --git a/tests/cpp/23962.h b/tests/cpp/23962.h
new file mode 100644
index 000000000..2d8147bfb
--- /dev/null
+++ b/tests/cpp/23962.h
@@ -0,0 +1,17 @@
+#include <iostream>
+
+struct Foo {
+
+  Foo(int inX): x(inX) {
+    std::cout << "Ctor Foo(" << x << ")\n";
+  }
+  ~Foo() {
+    std::cout << "Destory Foo(" << x << ")\n";
+  }
+
+  void print() {
+    std::cout << "Foo.x = " << x << '\n';
+  }
+
+  int x;
+};
\ No newline at end of file
diff --git a/tests/cpp/fam.h b/tests/cpp/fam.h
new file mode 100644
index 000000000..ad576425b
--- /dev/null
+++ b/tests/cpp/fam.h
@@ -0,0 +1,4 @@
+struct Test{
+  ~Test() {
+  }
+};
diff --git a/tests/cpp/t23657.nim b/tests/cpp/t23657.nim
new file mode 100644
index 000000000..63deb7fb0
--- /dev/null
+++ b/tests/cpp/t23657.nim
@@ -0,0 +1,54 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp -r $file"
+  output: '''
+1.0
+1.0
+'''
+
+"""
+{.emit:"""/*TYPESECTION*/
+struct Point {
+  float x, y, z;
+  Point(float x, float y, float z): x(x), y(y), z(z) {}
+  Point() = default;
+};
+struct Direction {
+  float x, y, z;
+  Direction(float x, float y, float z): x(x), y(y), z(z) {}
+  Direction() = default;
+};
+struct Axis {
+  Point origin;
+  Direction direction;
+  Axis(Point origin, Direction direction): origin(origin), direction(direction) {}
+  Axis() = default;
+};
+
+""".}
+
+type
+  Point {.importcpp.} = object
+    x, y, z: float
+  
+  Direction {.importcpp.} = object
+    x, y, z: float
+
+  Axis {.importcpp.} = object
+    origin: Point
+    direction: Direction
+
+proc makeAxis(origin: Point, direction: Direction): Axis {. constructor, importcpp:"Axis(@)".}
+proc makePoint(x, y, z: float): Point {. constructor, importcpp:"Point(@)".}
+proc makeDirection(x, y, z: float): Direction {. constructor, importcpp:"Direction(@)".}
+
+var axis1 = makeAxis(Point(x: 1.0, y: 2.0, z: 3.0), Direction(x: 4.0, y: 5.0, z: 6.0)) #Triggers the error (T1)
+var axis2Ctor = makeAxis(makePoint(1.0, 2.0, 3.0), makeDirection(4.0, 5.0, 6.0)) #Do not triggers
+
+proc main() = #Do not triggers as Tx are inside the body
+  let test = makeAxis(Point(x: 1.0, y: 2.0, z: 3.0), Direction(x: 4.0, y: 5.0, z: 6.0))
+  echo test.origin.x
+
+main()
+
+echo $axis1.origin.x  #Make sures it's init
\ No newline at end of file
diff --git a/tests/cpp/t23962.nim b/tests/cpp/t23962.nim
new file mode 100644
index 000000000..c79d888df
--- /dev/null
+++ b/tests/cpp/t23962.nim
@@ -0,0 +1,32 @@
+discard """
+  cmd: "nim cpp $file"
+  output: '''
+Ctor Foo(-1)
+Destory Foo(-1)
+Ctor Foo(-1)
+Destory Foo(-1)
+Ctor Foo(-1)
+Destory Foo(-1)
+Foo.x = 1
+Foo.x = 2
+Foo.x = -1
+'''
+"""
+
+type
+  Foo {.importcpp, header: "23962.h".} = object
+    x: cint
+
+proc print(f: Foo) {.importcpp.}
+
+#also tests the right constructor is used
+proc makeFoo(x: int32 = -1): Foo {.importcpp:"Foo(#)", constructor.} 
+
+proc test =
+  var xs = newSeq[Foo](3)
+  xs[0].x = 1
+  xs[1].x = 2
+  for x in xs:
+    x.print
+
+test()
\ No newline at end of file
diff --git a/tests/cpp/tcasts.nim b/tests/cpp/tcasts.nim
index d968d87db..80527efff 100644
--- a/tests/cpp/tcasts.nim
+++ b/tests/cpp/tcasts.nim
@@ -1,6 +1,5 @@
 discard """
   cmd: "nim cpp $file"
-  output: '''{"vas": "kas", "123": "123"}'''
   targets: "cpp"
 """
 
@@ -18,4 +17,4 @@ 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
+doAssert t.len == 2
diff --git a/tests/cpp/tfam.nim b/tests/cpp/tfam.nim
new file mode 100644
index 000000000..6bd89fe24
--- /dev/null
+++ b/tests/cpp/tfam.nim
@@ -0,0 +1,7 @@
+discard """
+  targets: "cpp"
+"""
+type 
+  Test {.importcpp, header: "fam.h".} = object
+
+let test = newSeq[Test]()
\ No newline at end of file
diff --git a/tests/destructor/t23748.nim b/tests/destructor/t23748.nim
new file mode 100644
index 000000000..a3738733e
--- /dev/null
+++ b/tests/destructor/t23748.nim
@@ -0,0 +1,31 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+  output: '''
+hello 42
+hello 42
+len = 2
+'''
+"""
+
+# bug #23748
+
+type
+  O = ref object
+    s: string
+    cb: seq[proc()]
+
+proc push1(o: O, i: int) =
+  let o = o
+  echo o.s, " ", i
+  o.cb.add(proc() = echo o.s, " ", i)
+
+proc push2(o: O, i: int) =
+  let o = o
+  echo o.s, " ", i
+  proc p() = echo o.s, " ", i
+  o.cb.add(p)
+
+let o = O(s: "hello", cb: @[])
+o.push1(42)
+o.push2(42)
+echo "len = ", o.cb.len
diff --git a/tests/destructor/t23837.nim b/tests/destructor/t23837.nim
new file mode 100644
index 000000000..e219dd6b5
--- /dev/null
+++ b/tests/destructor/t23837.nim
@@ -0,0 +1,51 @@
+discard """
+  output: '''
+Deallocating OwnedString
+HelloWorld
+'''
+  matrix: "--cursorinference:on; --cursorinference:off"
+  target: "c"
+"""
+
+# bug #23837
+{.
+  emit: [
+    """
+#include <stdlib.h>
+#include <string.h>
+char *allocCString() {
+    char *result = (char *) malloc(10 + 1);
+    strcpy(result, "HelloWorld");
+    return result;
+}
+
+"""
+  ]
+.}
+
+proc rawWrapper(): cstring {.importc: "allocCString", cdecl.}
+proc free(p: pointer) {.importc: "free", cdecl.}
+
+# -------------------------
+
+type OwnedString = distinct cstring
+
+proc `=destroy`(s: OwnedString) =
+  free(cstring s)
+  echo "Deallocating OwnedString"
+
+func `$`(s: OwnedString): string {.borrow.}
+
+proc leakyWrapper(): string =
+  let ostring = rawWrapper().OwnedString
+  $ostring
+
+# -------------------------
+
+proc main() =
+  # destructor not called - definitely lost: 11 bytes in 1 blocks
+  # doesn't leak with --cursorInference:off
+  let s = leakyWrapper()
+  echo s
+
+main()
\ No newline at end of file
diff --git a/tests/destructor/tatomicptrs.nim b/tests/destructor/tatomicptrs.nim
index 7bd5482b2..82870ac82 100644
--- a/tests/destructor/tatomicptrs.nim
+++ b/tests/destructor/tatomicptrs.nim
@@ -143,11 +143,13 @@ proc `=sink`*[T](m: var MySeq[T], m2: MySeq[T]) {.inline.} =
       `=destroy`(m)
     m.len = m2.len
     m.data = m2.data
+    m.refcount = m2.refcount
 
 proc len*[T](m: MySeq[T]): int {.inline.} = m.len
 
 proc newMySeq*[T](size: int, initial_value: T): MySeq[T] =
   result.len = size
+  result.refcount = 1
   if size > 0:
     result.data = cast[ptr UncheckedArray[T]](allocShared(sizeof(T) * size))
 
diff --git a/tests/destructor/tdistinctseq.nim b/tests/destructor/tdistinctseq.nim
new file mode 100644
index 000000000..5a2ac5ead
--- /dev/null
+++ b/tests/destructor/tdistinctseq.nim
@@ -0,0 +1,8 @@
+discard """
+  matrix: "-u:nimPreviewNonVarDestructor;"
+"""
+type DistinctSeq* = distinct seq[int]
+
+# `=destroy`(cast[ptr DistinctSeq](0)[])
+var x = @[].DistinctSeq
+`=destroy`(x)
diff --git a/tests/destructor/tgotoexc_leak.nim b/tests/destructor/tgotoexc_leak.nim
new file mode 100644
index 000000000..c8a234085
--- /dev/null
+++ b/tests/destructor/tgotoexc_leak.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''0
+true'''
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #22398
+
+for i in 0 ..< 10_000:
+  try:
+    try:
+      raise newException(ValueError, "")
+    except CatchableError:
+      discard
+      raise newException(ValueError, "") # or raise getCurrentException(), just raise works ok
+  except ValueError:
+    discard
+echo getOccupiedMem()
+echo getCurrentException() == nil
diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim
index a583a1704..cdc1eb1c0 100644
--- a/tests/destructor/tmove_objconstr.nim
+++ b/tests/destructor/tmove_objconstr.nim
@@ -137,28 +137,29 @@ doAssert seq3[0] == 1.0
 var seq4, seq5: MySeqNonCopyable
 (seq4, i, seq5) = myfunc2(2, 3)
 
-seq4 = block:
-  var tmp = newMySeq(4, 1.0)
-  tmp[0] = 3.0
-  tmp
+proc foo =
+  seq4 = block:
+    var tmp = newMySeq(4, 1.0)
+    tmp[0] = 3.0
+    tmp
 
-doAssert seq4[0] == 3.0
+  doAssert seq4[0] == 3.0
 
-import macros
 
-seq4 =
-  if i > 0: newMySeq(2, 5.0)
-  elif i < -100: raise newException(ValueError, "Parse Error")
-  else: newMySeq(2, 3.0)
+  seq4 =
+    if i > 0: newMySeq(2, 5.0)
+    elif i < -100: raise newException(ValueError, "Parse Error")
+    else: newMySeq(2, 3.0)
 
-seq4 =
-  case (char) i:
-    of 'A', {'W'..'Z'}: newMySeq(2, 5.0)
-    of 'B': quit(-1)
-    else:
-      let (x1, x2, x3) = myfunc2(2, 3)
-      x3
+  seq4 =
+    case (char) i:
+      of 'A', {'W'..'Z'}: newMySeq(2, 5.0)
+      of 'B': quit(-1)
+      else:
+        let (x1, x2, x3) = myfunc2(2, 3)
+        x3
 
+foo()
 
 #------------------------------------------------------------
 #-- Move into array constructor
diff --git a/tests/destructor/tsink.nim b/tests/destructor/tsink.nim
index 82cbdfbe5..e8750ad7c 100644
--- a/tests/destructor/tsink.nim
+++ b/tests/destructor/tsink.nim
@@ -14,3 +14,57 @@ proc foo = # bug #23359
   doAssert bar.value == 42
 
 foo()
+
+block: # bug #23902
+  proc foo(a: sink string): auto = (a, a)
+
+  proc bar(a: sink int): auto = return a
+
+  proc foo(a: sink string) =
+    var x = (a, a)
+
+block: # bug #24175
+  block:
+    func mutate(o: sink string): string =
+      o[1] = '1'
+      result = o
+
+    static:
+      let s = "999"
+      let m = mutate(s)
+      doAssert s == "999"
+      doAssert m == "919"
+
+    func foo() =
+      let s = "999"
+      let m = mutate(s)
+      doAssert s == "999"
+      doAssert m == "919"
+
+    static:
+      foo()
+    foo()
+
+  block:
+    type O = object
+      a: int
+
+    func mutate(o: sink O): O =
+      o.a += 1
+      o
+
+    static:
+      let x = O(a: 1)
+      let y = mutate(x)
+      doAssert x.a == 1
+      doAssert y.a == 2
+
+    proc foo() =
+      let x = O(a: 1)
+      let y = mutate(x)
+      doAssert x.a == 1
+      doAssert y.a == 2
+
+    static:
+      foo()
+    foo()
diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim
index 4ff2dc9a0..48bdf67dd 100644
--- a/tests/destructor/tv2_cast.nim
+++ b/tests/destructor/tv2_cast.nim
@@ -10,69 +10,41 @@ destroying O1'''
 var
   data
   :tmpD
-  :tmpD_1
-  :tmpD_2
-data =
-  :tmpD = `=dup`(cast[string](
-    :tmpD_2 = encode(cast[seq[byte]](
-      :tmpD_1 = newString(100)
-      :tmpD_1))
-    :tmpD_2))
-  :tmpD
-`=destroy`(:tmpD_2)
-`=destroy_1`(:tmpD_1)
-`=destroy_1`(data)
+data = cast[string](encode(cast[seq[byte]](
+  :tmpD = newString(100)
+  :tmpD)))
+`=destroy`(:tmpD)
+`=destroy`(data)
 -- end of expandArc ------------------------
 --expandArc: main1
 
 var
   s
   data
-  :tmpD
-  :tmpD_1
 s = newString(100)
-data =
-  :tmpD = `=dup`(cast[string](
-    :tmpD_1 = encode(toOpenArrayByte(s, 0, len(s) - 1))
-    :tmpD_1))
-  :tmpD
-`=destroy`(:tmpD_1)
-`=destroy_1`(data)
-`=destroy_1`(s)
+data = cast[string](encode(toOpenArrayByte(s, 0, len(s) - 1)))
+`=destroy`(data)
+`=destroy`(s)
 -- end of expandArc ------------------------
 --expandArc: main2
 
 var
   s
   data
-  :tmpD
-  :tmpD_1
 s = newSeq(100)
-data =
-  :tmpD = `=dup`(cast[string](
-    :tmpD_1 = encode(s)
-    :tmpD_1))
-  :tmpD
-`=destroy`(:tmpD_1)
-`=destroy_1`(data)
-`=destroy`(s)
+data = cast[string](encode(s))
+`=destroy`(data)
+`=destroy_1`(s)
 -- end of expandArc ------------------------
 --expandArc: main3
 
 var
   data
   :tmpD
-  :tmpD_1
-  :tmpD_2
-data =
-  :tmpD = `=dup`(cast[string](
-    :tmpD_2 = encode do:
-      :tmpD_1 = newSeq(100)
-      :tmpD_1
-    :tmpD_2))
-  :tmpD
-`=destroy`(:tmpD_2)
-`=destroy`(:tmpD_1)
+data = cast[string](encode do:
+  :tmpD = newSeq(100)
+  :tmpD)
+`=destroy`(:tmpD)
 `=destroy_1`(data)
 -- end of expandArc ------------------------
 '''
diff --git a/tests/discard/t23677.nim b/tests/discard/t23677.nim
new file mode 100644
index 000000000..1ed7386bd
--- /dev/null
+++ b/tests/discard/t23677.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "expression '0' is of type 'int literal(0)' and has to be used (or discarded); start of expression here: t23677.nim(1, 1)"
+  line: 10
+  column: 3
+"""
+
+# issue #23677
+
+if true:
+  0
+else: 
+  raise newException(ValueError, "err") 
diff --git a/tests/discard/tdiscardable.nim b/tests/discard/tdiscardable.nim
index 69cb9f6a1..84b669ed8 100644
--- a/tests/discard/tdiscardable.nim
+++ b/tests/discard/tdiscardable.nim
@@ -5,6 +5,7 @@ tdiscardable
 1
 something defered
 something defered
+hi
 '''
 """
 
@@ -110,3 +111,65 @@ block:
 
   doAssertRaises(ValueError):
     doAssert foo() == 12
+
+block: # issue #10440
+  proc x(): int {.discardable.} = discard
+  try:
+    x()
+  finally:
+    echo "hi"
+
+import macros
+
+block: # issue #14665
+  macro test(): untyped =   
+    let b = @[1, 2, 3, 4]
+
+    result = nnkStmtList.newTree()
+    var i = 0
+    while i < b.len:
+      if false:
+        # this quote do is mandatory, removing it fixes the problem
+        result.add quote do:
+          let testtest = 5
+      else:
+        result.add quote do:
+          let test = 6
+        inc i
+        # removing this continue fixes the problem too
+        continue
+      inc i
+  test()
+
+block: # bug #23775
+  proc retInt(): int {.discardable.} =
+    42
+
+  proc retString(): string {.discardable.} =
+    "text"
+
+  type
+    Enum = enum
+      A, B, C, D
+
+  proc doStuff(msg: Enum) =
+    case msg:
+    of A:
+      retString()
+    of B:
+      retInt()
+    of C:
+      discard retString()
+    else:
+      let _ = retString()
+
+  doStuff(C)
+
+block:
+  proc test(): (int, int) {.discardable.} =
+    discard
+
+  if true:
+    test()
+  else:
+    quit()
diff --git a/tests/discard/tfinallyerrmsg.nim b/tests/discard/tfinallyerrmsg.nim
new file mode 100644
index 000000000..fbc8140aa
--- /dev/null
+++ b/tests/discard/tfinallyerrmsg.nim
@@ -0,0 +1,19 @@
+discard """
+  cmd: "nim check $file"
+"""
+
+block: # issue #19672
+  try:
+    10 #[tt.Error
+    ^ expression '10' is of type 'int literal(10)' and has to be used (or discarded); start of expression here: tfinallyerrmsg.nim(5, 1)]#
+  finally:
+    echo "Finally block"
+
+block: # issue #13871
+  template t(body: int) =
+    try:
+      body
+    finally:
+      echo "expression"
+  t: 2 #[tt.Error
+     ^ expression '2' is of type 'int literal(2)' and has to be used (or discarded)]#
diff --git a/tests/distinct/tcomplexaddressableconv.nim b/tests/distinct/tcomplexaddressableconv.nim
new file mode 100644
index 000000000..00e96bfeb
--- /dev/null
+++ b/tests/distinct/tcomplexaddressableconv.nim
@@ -0,0 +1,21 @@
+# issue #22523
+
+from std/typetraits import distinctBase
+
+type
+  V[p: static int] = distinct int
+  D[p: static int] = distinct int
+  T = V[1]
+
+proc f(y: var T) = discard
+
+var a: D[0]
+
+static:
+  doAssert distinctBase(T) is distinctBase(D[0])
+  doAssert distinctBase(T) is int
+  doAssert distinctBase(D[0]) is int
+  doAssert T(a) is T
+
+f(cast[ptr T](addr a)[])
+f(T(a))
diff --git a/tests/enum/tenum.nim b/tests/enum/tenum.nim
index 8046c6589..a03019c5d 100644
--- a/tests/enum/tenum.nim
+++ b/tests/enum/tenum.nim
@@ -184,3 +184,84 @@ block: # bug #12589
           A = int64.high()
 
       doAssert ord(A) == int64.high()
+
+import std/enumutils
+from std/sequtils import toSeq
+import std/macros
+
+block: # unordered enum
+  block:
+    type
+      unordered_enum = enum
+        a = 1
+        b = 0
+
+    doAssert (ord(a), ord(b)) == (1, 0)
+    doAssert unordered_enum.toSeq == @[a, b]
+
+  block:
+    type
+      unordered_enum = enum
+        a = 1
+        b = 0
+        c
+
+    doAssert (ord(a), ord(b), ord(c)) == (1, 0, 2)
+
+  block:
+    type
+      unordered_enum = enum
+        a = 100
+        b
+        c = 50
+        d
+
+    doAssert (ord(a), ord(b), ord(c), ord(d)) == (100, 101, 50, 51)
+
+  block:
+    type
+      unordered_enum = enum
+        a = 7
+        b = 6
+        c = 5
+        d
+
+    doAssert (ord(a), ord(b), ord(c), ord(d)) == (7, 6, 5, 8)
+    doAssert unordered_enum.toSeq == @[a, b, c, d]
+
+  block:
+    type
+      unordered_enum = enum
+        a = 100
+        b
+        c = 500
+        d
+        e
+        f = 50
+        g
+        h
+
+    doAssert (ord(a), ord(b), ord(c), ord(d), ord(e), ord(f), ord(g), ord(h)) == 
+             (100, 101, 500, 501, 502, 50, 51, 52)
+
+  block:
+    type
+      unordered_enum = enum
+        A
+        B
+        C = -1
+        D
+        E
+        G = -999
+
+    doAssert (ord(A), ord(B), ord(C), ord(D), ord(E), ord(G)) ==
+             (0, 1, -1, 2, 3, -999)
+
+  block:
+    type
+      SomeEnum = enum
+        seA = 3
+        seB = 2
+        seC = "foo"
+
+    doAssert (ord(seA), ord(seB), ord(seC)) == (3, 2, 4)
diff --git a/tests/enum/tenum_duplicate.nim b/tests/enum/tenum_duplicate.nim
new file mode 100644
index 000000000..4bcad7f6f
--- /dev/null
+++ b/tests/enum/tenum_duplicate.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "duplicate value in enum 'd'"
+"""
+
+type
+  unordered_enum = enum
+    a = 1
+    b = 0
+    c
+    d = 2
diff --git a/tests/enum/toverloadedname.nim b/tests/enum/toverloadedname.nim
new file mode 100644
index 000000000..d11b0fb83
--- /dev/null
+++ b/tests/enum/toverloadedname.nim
@@ -0,0 +1,7 @@
+block: # issue #23998
+  type
+    Enum {.pure.} = enum
+      a
+    Obj = object
+      a: Enum
+  proc test(a: Enum) = discard Obj(a: a)
diff --git a/tests/enum/tpure_enums_conflict.nim b/tests/enum/tpure_enums_conflict.nim
index 4411fd2a6..3cf335440 100644
--- a/tests/enum/tpure_enums_conflict.nim
+++ b/tests/enum/tpure_enums_conflict.nim
@@ -1,7 +1,5 @@
 discard """
-  disabled: true # pure enums behave like overloaded enums on ambiguity now which gives a different error message
-  errormsg: "ambiguous identifier: 'amb'"
-  line: 19
+  matrix: "-d:testsConciseTypeMismatch"
 """
 
 # bug #8066
@@ -17,4 +15,13 @@ when true:
 
   echo valueA # MyEnum.valueA
   echo MyEnum.amb # OK.
-  echo amb    # Error: Unclear whether it's MyEnum.amb or OtherEnum.amb
+  echo amb #[tt.Error
+  ^ type mismatch
+Expression: echo amb
+  [1] amb: MyEnum | OtherEnum
+
+Expected one of (first mismatch at [position]):
+[1] proc echo(x: varargs[typed, `$$`])
+  ambiguous identifier: 'amb' -- use one of the following:
+    MyEnum.amb: MyEnum
+    OtherEnum.amb: OtherEnum]#
diff --git a/tests/enum/tpure_enums_conflict_legacy.nim b/tests/enum/tpure_enums_conflict_legacy.nim
new file mode 100644
index 000000000..e592925bc
--- /dev/null
+++ b/tests/enum/tpure_enums_conflict_legacy.nim
@@ -0,0 +1,25 @@
+# bug #8066
+
+when true:
+  type
+    MyEnum {.pure.} = enum
+      valueA, valueB, valueC, valueD, amb
+
+    OtherEnum {.pure.} = enum
+      valueX, valueY, valueZ, amb
+
+
+  echo valueA # MyEnum.valueA
+  echo MyEnum.amb # OK.
+  echo amb #[tt.Error
+  ^ type mismatch: got <MyEnum | OtherEnum>
+but expected one of:
+proc echo(x: varargs[typed, `$$`])
+  first type mismatch at position: 1
+  required type for x: varargs[typed]
+  but expression 'amb' is of type: None
+  ambiguous identifier: 'amb' -- use one of the following:
+    MyEnum.amb: MyEnum
+    OtherEnum.amb: OtherEnum
+
+expression: echo amb]#
diff --git a/tests/enum/ttypenameconflict.nim b/tests/enum/ttypenameconflict.nim
new file mode 100644
index 000000000..b13bf00ce
--- /dev/null
+++ b/tests/enum/ttypenameconflict.nim
@@ -0,0 +1,13 @@
+# issue #23689
+
+type
+  MyEnum {.pure.} = enum
+    A, B, C, D
+
+  B = object
+    field: int
+
+let x: MyEnum = B
+doAssert $x == "B"
+doAssert typeof(x) is MyEnum
+doAssert x in {A, B}
diff --git a/tests/errmsgs/mambparam1.nim b/tests/errmsgs/mambparam1.nim
new file mode 100644
index 000000000..1a5133c3c
--- /dev/null
+++ b/tests/errmsgs/mambparam1.nim
@@ -0,0 +1 @@
+const test* = "foo"
diff --git a/tests/errmsgs/mambparam2.nim b/tests/errmsgs/mambparam2.nim
new file mode 100644
index 000000000..073e3f8c8
--- /dev/null
+++ b/tests/errmsgs/mambparam2.nim
@@ -0,0 +1,2 @@
+import mambparam1
+export test
diff --git a/tests/errmsgs/mambparam3.nim b/tests/errmsgs/mambparam3.nim
new file mode 100644
index 000000000..5469244e2
--- /dev/null
+++ b/tests/errmsgs/mambparam3.nim
@@ -0,0 +1 @@
+const test* = "bar"
diff --git a/tests/errmsgs/t10735.nim b/tests/errmsgs/t10735.nim
index f480d35ac..a39cd196e 100644
--- a/tests/errmsgs/t10735.nim
+++ b/tests/errmsgs/t10735.nim
@@ -2,40 +2,62 @@ discard """
   cmd: "nim check $file"
   errormsg: "illformed AST: case buf[pos]"
   nimout: '''
-t10735.nim(43, 5) Error: 'let' symbol requires an initialization
-t10735.nim(44, 10) Error: undeclared identifier: 'pos'
-t10735.nim(44, 10) Error: expression 'pos' has no type (or is ambiguous)
-t10735.nim(44, 10) Error: expression 'pos' has no type (or is ambiguous)
-t10735.nim(44, 9) Error: type mismatch: got <cstring, >
+t10735.nim(65, 5) Error: 'let' symbol requires an initialization
+t10735.nim(66, 10) Error: undeclared identifier: 'pos'
+t10735.nim(66, 10) Error: expression 'pos' has no type (or is ambiguous)
+t10735.nim(66, 10) Error: expression 'pos' has no type (or is ambiguous)
+t10735.nim(66, 9) Error: type mismatch: got <cstring, >
 but expected one of:
 proc `[]`(s: string; i: BackwardsIndex): char
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: string
+  but expression 'buf' is of type: cstring
 proc `[]`(s: var string; i: BackwardsIndex): var char
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: var string
+  but expression 'buf' is of type: cstring
 proc `[]`[I: Ordinal; T](a: T; i: I): T
   first type mismatch at position: 0
 proc `[]`[Idx, T; U, V: Ordinal](a: array[Idx, T]; x: HSlice[U, V]): seq[T]
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for a: array[Idx, T]
+  but expression 'buf' is of type: cstring
 proc `[]`[Idx, T](a: array[Idx, T]; i: BackwardsIndex): T
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for a: array[Idx, T]
+  but expression 'buf' is of type: cstring
 proc `[]`[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for a: var array[Idx, T]
+  but expression 'buf' is of type: cstring
 proc `[]`[T, U: Ordinal](s: string; x: HSlice[T, U]): string
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: string
+  but expression 'buf' is of type: cstring
 proc `[]`[T; U, V: Ordinal](s: openArray[T]; x: HSlice[U, V]): seq[T]
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: openArray[T]
+  but expression 'buf' is of type: cstring
 proc `[]`[T](s: openArray[T]; i: BackwardsIndex): T
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: openArray[T]
+  but expression 'buf' is of type: cstring
 proc `[]`[T](s: var openArray[T]; i: BackwardsIndex): var T
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: var openArray[T]
+  but expression 'buf' is of type: cstring
 template `[]`(a: WideCStringObj; idx: int): Utf16Char
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for a: WideCStringObj
+  but expression 'buf' is of type: cstring
 template `[]`(s: string; i: int): char
-  first type mismatch at position: 0
+  first type mismatch at position: 1
+  required type for s: string
+  but expression 'buf' is of type: cstring
 
-expression: `[]`(buf, pos)
-t10735.nim(44, 9) Error: expression '' has no type (or is ambiguous)
-t10735.nim(46, 3) Error: illformed AST: case buf[pos]
+expression: buf[pos]
+t10735.nim(66, 9) Error: expression '' has no type (or is ambiguous)
+t10735.nim(68, 3) Error: illformed AST: case buf[pos]
 '''
   joinable: false
 """
diff --git a/tests/errmsgs/t22097.nim b/tests/errmsgs/t22097.nim
index b50db08a3..bb24ee8d3 100644
--- a/tests/errmsgs/t22097.nim
+++ b/tests/errmsgs/t22097.nim
@@ -1,9 +1,9 @@
 discard """
-  errormsg: "for a 'var' type a variable needs to be passed; but 'uint16(x)' is immutable"
+  errormsg: "type mismatch: got <uint8>"
 """
 
 proc toUInt16(x: var uint16) =
   discard
 
 var x = uint8(1)
-toUInt16 x
\ No newline at end of file
+toUInt16 x
diff --git a/tests/errmsgs/t22753.nim b/tests/errmsgs/t22753.nim
index af6a871f1..8a504109a 100644
--- a/tests/errmsgs/t22753.nim
+++ b/tests/errmsgs/t22753.nim
@@ -3,33 +3,50 @@ cmd: "nim check --hints:off $file"
 errormsg: "type mismatch"
 nimoutFull: true
 nimout: '''
-t22753.nim(34, 13) Error: array expects two type parameters
-t22753.nim(35, 1) Error: expression 'x' has no type (or is ambiguous)
-t22753.nim(35, 1) Error: expression 'x' has no type (or is ambiguous)
-t22753.nim(35, 2) Error: type mismatch: got <>
+t22753.nim(51, 13) Error: array expects two type parameters
+t22753.nim(52, 1) Error: expression 'x' has no type (or is ambiguous)
+t22753.nim(52, 1) Error: expression 'x' has no type (or is ambiguous)
+t22753.nim(52, 2) Error: type mismatch: got <>
 but expected one of:
 proc `[]=`(s: var string; i: BackwardsIndex; x: char)
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for i: BackwardsIndex
+  but expression '0' is of type: int literal(0)
 proc `[]=`[I: Ordinal; T, S](a: T; i: I; x: sink S)
   first type mismatch at position: 0
 proc `[]=`[Idx, T; U, V: Ordinal](a: var array[Idx, T]; x: HSlice[U, V];
                                   b: openArray[T])
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for x: HSlice[[]=.U, []=.V]
+  but expression '0' is of type: int literal(0)
 proc `[]=`[Idx, T](a: var array[Idx, T]; i: BackwardsIndex; x: T)
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for i: BackwardsIndex
+  but expression '0' is of type: int literal(0)
 proc `[]=`[T, U: Ordinal](s: var string; x: HSlice[T, U]; b: string)
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for x: HSlice[[]=.T, []=.U]
+  but expression '0' is of type: int literal(0)
 proc `[]=`[T; U, V: Ordinal](s: var seq[T]; x: HSlice[U, V]; b: openArray[T])
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for x: HSlice[[]=.U, []=.V]
+  but expression '0' is of type: int literal(0)
 proc `[]=`[T](s: var openArray[T]; i: BackwardsIndex; x: T)
-  first type mismatch at position: 0
+  first type mismatch at position: 2
+  required type for i: BackwardsIndex
+  but expression '0' is of type: int literal(0)
 template `[]=`(a: WideCStringObj; idx: int; val: Utf16Char)
-  first type mismatch at position: 0
+  first type mismatch at position: 3
+  required type for val: Utf16Char
+  but expression '9' is of type: int literal(9)
 template `[]=`(s: string; i: int; val: char)
-  first type mismatch at position: 0
+  first type mismatch at position: 3
+  required type for val: char
+  but expression '9' is of type: int literal(9)
 
-expression: `[]=`(x, 0, 9)
+expression: x[0] = 9
 '''
 """
+
 var x: array[3] # bug #22753
-x[0] = 9
\ No newline at end of file
+x[0] = 9
diff --git a/tests/errmsgs/t22852.nim b/tests/errmsgs/t22852.nim
new file mode 100644
index 000000000..7c352a49c
--- /dev/null
+++ b/tests/errmsgs/t22852.nim
@@ -0,0 +1,9 @@
+discard """
+  exitcode: 1
+  outputsub: '''
+Error: unhandled exception: value out of range: -2 notin 0 .. 9223372036854775807 [RangeDefect]
+'''
+"""
+
+# bug #22852
+echo [0][2..^2]
diff --git a/tests/errmsgs/t23419.nim b/tests/errmsgs/t23419.nim
new file mode 100644
index 000000000..59a72f081
--- /dev/null
+++ b/tests/errmsgs/t23419.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "invalid type: 'void' in this context: '(array[0..-1, void],)' for var"
+"""
+
+var a: (array[0, void], )
diff --git a/tests/errmsgs/t23536.nim b/tests/errmsgs/t23536.nim
new file mode 100644
index 000000000..610a85bab
--- /dev/null
+++ b/tests/errmsgs/t23536.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--stackTrace:on --excessiveStackTrace:off"
+"""
+
+const expected = """
+wrong trace:
+t23536.nim(22)           t23536
+t23536.nim(17)           foo
+assertions.nim(41)       failedAssertImpl
+assertions.nim(36)       raiseAssert
+fatal.nim(53)            sysFatal
+"""
+
+
+try:
+  proc foo = # bug #23536
+    doAssert false
+
+  for i in 0 .. 1:
+
+
+    foo()
+except AssertionDefect:
+  let e = getCurrentException()
+  let trace = e.getStackTrace
+  doAssert "wrong trace:\n" & trace == expected
diff --git a/tests/errmsgs/tambparam.nim b/tests/errmsgs/tambparam.nim
new file mode 100644
index 000000000..5b56a3fce
--- /dev/null
+++ b/tests/errmsgs/tambparam.nim
@@ -0,0 +1,16 @@
+discard """
+  matrix: "-d:testsConciseTypeMismatch"
+"""
+
+import mambparam2, mambparam3
+
+echo test #[tt.Error
+^ type mismatch
+Expression: echo test
+  [1] test: string | string
+
+Expected one of (first mismatch at [position]):
+[1] proc echo(x: varargs[typed, `$$`])
+  ambiguous identifier: 'test' -- use one of the following:
+    mambparam1.test: string
+    mambparam3.test: string]#
diff --git a/tests/errmsgs/tambparam_legacy.nim b/tests/errmsgs/tambparam_legacy.nim
new file mode 100644
index 000000000..bd99a3aac
--- /dev/null
+++ b/tests/errmsgs/tambparam_legacy.nim
@@ -0,0 +1,14 @@
+import mambparam2, mambparam3
+
+echo test #[tt.Error
+^ type mismatch: got <string | string>
+but expected one of:
+proc echo(x: varargs[typed, `$$`])
+  first type mismatch at position: 1
+  required type for x: varargs[typed]
+  but expression 'test' is of type: None
+  ambiguous identifier: 'test' -- use one of the following:
+    mambparam1.test: string
+    mambparam3.test: string
+
+expression: echo test]#
diff --git a/tests/errmsgs/tconcisetypemismatch.nim b/tests/errmsgs/tconcisetypemismatch.nim
index c2896604f..3093cc24e 100644
--- a/tests/errmsgs/tconcisetypemismatch.nim
+++ b/tests/errmsgs/tconcisetypemismatch.nim
@@ -1,5 +1,5 @@
 discard """
-  cmd: "nim c --hints:off --skipParentCfg $file"
+  cmd: "nim c --hints:off -d:testsConciseTypeMismatch $file"
   errormsg: "type mismatch"
   nimout: '''
 tconcisetypemismatch.nim(23, 47) Error: type mismatch
diff --git a/tests/errmsgs/tconcisetypemismatch.nims b/tests/errmsgs/tconcisetypemismatch.nims
deleted file mode 100644
index e9dce8147..000000000
--- a/tests/errmsgs/tconcisetypemismatch.nims
+++ /dev/null
@@ -1,21 +0,0 @@
-switch("path", "$lib/../testament/lib")
-  # so we can `import stdtest/foo` inside tests
-  # Using $lib/../ instead of $nim/ so you can use a different nim to run tests
-  # during local testing, e.g. nim --lib:lib.
-
-## prevent common user config settings to interfere with testament expectations
-## Indifidual tests can override this if needed to test for these options.
-switch("colors", "off")
-
-switch("excessiveStackTrace", "off")
-
-when (NimMajor, NimMinor, NimPatch) >= (1,5,1):
-  # to make it easier to test against older nim versions, (best effort only)
-  switch("filenames", "legacyRelProj")
-  switch("spellSuggest", "0")
-
-# for std/unittest
-switch("define", "nimUnittestOutputLevel:PRINT_FAILURES")
-switch("define", "nimUnittestColor:off")
-
-hint("Processing", off)
diff --git a/tests/errmsgs/tgenericmismatchsegfault.nim b/tests/errmsgs/tgenericmismatchsegfault.nim
new file mode 100644
index 000000000..dbb783cb3
--- /dev/null
+++ b/tests/errmsgs/tgenericmismatchsegfault.nim
@@ -0,0 +1,13 @@
+discard """
+  matrix: "-d:testsConciseTypeMismatch"
+"""
+
+template v[T](c: SomeOrdinal): T = T(c)
+discard v[int, char]('A') #[tt.Error
+                    ^ type mismatch
+Expression: v[int, char]('A')
+  [1] 'A': char
+
+Expected one of (first mismatch at [position]):
+[2] template v[T](c: SomeOrdinal): T
+  generic parameter mismatch, expected SomeOrdinal but got 'char' of type: char]#
diff --git a/tests/errmsgs/tgenericmismatchsegfault_legacy.nim b/tests/errmsgs/tgenericmismatchsegfault_legacy.nim
new file mode 100644
index 000000000..1532611b9
--- /dev/null
+++ b/tests/errmsgs/tgenericmismatchsegfault_legacy.nim
@@ -0,0 +1,10 @@
+template v[T](c: SomeOrdinal): T = T(c)
+discard v[int, char]('A') #[tt.Error
+                    ^ type mismatch: got <char>
+but expected one of:
+template v[T](c: SomeOrdinal): T
+  first type mismatch at position: 2 in generic parameters
+  required type for SomeOrdinal: SomeOrdinal
+  but expression 'char' is of type: char
+
+expression: v[int, char]('A')]#
diff --git a/tests/errmsgs/tinconsistentgensym.nim b/tests/errmsgs/tinconsistentgensym.nim
index 026c17fca..8e4c85106 100644
--- a/tests/errmsgs/tinconsistentgensym.nim
+++ b/tests/errmsgs/tinconsistentgensym.nim
@@ -7,7 +7,7 @@ block:
     when false:
       let x = 123
     else:
-      template x: untyped = 456
+      template x: untyped {.inject.} = 456
     echo x #[tt.Error
          ^ undeclared identifier: 'x`gensym0'; if declared in a template, this identifier may be inconsistently marked inject or gensym]#
   foo()
diff --git a/tests/errmsgs/tmetaobjectfields.nim b/tests/errmsgs/tmetaobjectfields.nim
new file mode 100644
index 000000000..47d3acf18
--- /dev/null
+++ b/tests/errmsgs/tmetaobjectfields.nim
@@ -0,0 +1,75 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  action: "reject"
+  nimout: '''
+tmetaobjectfields.nim(26, 5) Error: 'array' is not a concrete type
+tmetaobjectfields.nim(30, 5) Error: 'seq' is not a concrete type
+tmetaobjectfields.nim(34, 5) Error: 'set' is not a concrete type
+tmetaobjectfields.nim(37, 3) Error: 'sink' is not a concrete type
+tmetaobjectfields.nim(39, 3) Error: 'lent' is not a concrete type
+tmetaobjectfields.nim(56, 16) Error: 'seq' is not a concrete type
+tmetaobjectfields.nim(60, 5) Error: 'ptr' is not a concrete type
+tmetaobjectfields.nim(61, 5) Error: 'ref' is not a concrete type
+tmetaobjectfields.nim(62, 5) Error: 'auto' is not a concrete type
+tmetaobjectfields.nim(63, 5) Error: 'UncheckedArray' is not a concrete type
+tmetaobjectfields.nim(68, 5) Error: 'object' is not a concrete type
+tmetaobjectfields.nim(72, 5) Error: 'Type3011:ObjectType' is not a concrete type
+'''
+"""
+
+
+# bug #6982
+# bug #19546
+# bug #23531
+type
+  ExampleObj1 = object
+    arr: array
+
+type
+  ExampleObj2 = object
+    arr: seq
+
+type
+  ExampleObj3 = object
+    arr: set
+
+type A = object
+  b: sink
+  # a: openarray
+  c: lent
+
+type PropertyKind = enum
+  tInt,
+  tFloat,
+  tBool,
+  tString,
+  tArray
+
+type
+  Property = ref PropertyObj
+  PropertyObj = object
+    case kind: PropertyKind
+    of tInt: intValue: int
+    of tFloat: floatValue: float
+    of tBool: boolValue: bool
+    of tString: stringValue: string
+    of tArray: arrayValue: seq
+
+type
+  RegressionTest = object
+    a: ptr
+    b: ref
+    c: auto
+    d: UncheckedArray
+
+# bug #3011
+type
+  Type3011 = ref object 
+    context: ref object
+
+type
+  Value3011 = ref object
+    typ: Type3011
+
+proc x3011(): Value3011 =
+  nil
diff --git a/tests/errmsgs/tsubscriptmismatch.nim b/tests/errmsgs/tsubscriptmismatch.nim
new file mode 100644
index 000000000..a2b297b68
--- /dev/null
+++ b/tests/errmsgs/tsubscriptmismatch.nim
@@ -0,0 +1,11 @@
+discard """
+  matrix: "-d:testsConciseTypeMismatch"
+  nimout: '''
+[1] proc `[]`[T; U, V: Ordinal](s: openArray[T]; x: HSlice[U, V]): seq[T]
+'''
+"""
+
+type Foo = object
+let x = Foo()
+discard x[1] #[tt.Error
+         ^ type mismatch]#
diff --git a/tests/errmsgs/tsubscriptmismatch_legacy.nim b/tests/errmsgs/tsubscriptmismatch_legacy.nim
new file mode 100644
index 000000000..3e1f1eb71
--- /dev/null
+++ b/tests/errmsgs/tsubscriptmismatch_legacy.nim
@@ -0,0 +1,10 @@
+discard """
+  nimout: '''
+  but expression 'x' is of type: Foo
+'''
+"""
+
+type Foo = object
+let x = Foo()
+discard x[1] #[tt.Error
+         ^ type mismatch: got <Foo, int literal(1)>]#
diff --git a/tests/errmsgs/tundeclared_routine.nim b/tests/errmsgs/tundeclared_routine.nim
index 2f1320fff..41b1d35f4 100644
--- a/tests/errmsgs/tundeclared_routine.nim
+++ b/tests/errmsgs/tundeclared_routine.nim
@@ -9,7 +9,7 @@ tundeclared_routine.nim(29, 28) Error: invalid pragma: myPragma
 tundeclared_routine.nim(36, 13) Error: undeclared field: 'bar3' for type tundeclared_routine.Foo [type declared in tundeclared_routine.nim(33, 8)]
   found tundeclared_routine.bar3() [iterator declared in tundeclared_routine.nim(35, 12)]
 tundeclared_routine.nim(41, 13) Error: undeclared field: 'bar4' for type tundeclared_routine.Foo [type declared in tundeclared_routine.nim(39, 8)]
-tundeclared_routine.nim(44, 15) Error: attempting to call routine: 'bad5'
+tundeclared_routine.nim(44, 11) Error: undeclared identifier: 'bad5'
 '''
 """
 
diff --git a/tests/errmsgs/tuntypedoverload.nim b/tests/errmsgs/tuntypedoverload.nim
new file mode 100644
index 000000000..1b1c2809c
--- /dev/null
+++ b/tests/errmsgs/tuntypedoverload.nim
@@ -0,0 +1,37 @@
+discard """
+  cmd: "nim check $file"
+"""
+
+block:
+  template foo(x: var int, y: untyped) = discard
+  var a: float
+  foo(a, undeclared) #[tt.Error
+     ^ type mismatch: got <float, untyped>]# # `untyped` is arbitary
+  # previous error: undeclared identifier: 'undeclared'
+
+block: # issue #8697
+  type
+    Fruit = enum
+      apple
+      banana
+      orange
+  macro hello(x, y: untyped) = discard
+  hello(apple, banana, orange) #[tt.Error
+       ^ type mismatch: got <Fruit, Fruit, Fruit>]#
+
+block: # issue #23265
+  template declareFoo(fooName: untyped, value: uint16) =
+    const `fooName Value` {.inject.} = value
+
+  declareFoo(FOO, 0xFFFF)
+  declareFoo(BAR, 0xFFFFF) #[tt.Error
+            ^ type mismatch: got <untyped, int literal(1048575)>]#
+
+block: # issue #9620
+  template forLoop(index: untyped, length: int{lvalue}, body: untyped) =
+    for `index`{.inject.} in 0 ..< length:
+      body
+  var x = newSeq[int](10)
+  forLoop(i, x.len): #[tt.Error
+         ^ type mismatch: got <untyped, int, void>]#
+    x[i] = i
diff --git a/tests/errmsgs/twrong_explicit_typeargs.nim b/tests/errmsgs/twrong_explicit_typeargs.nim
new file mode 100644
index 000000000..5236e5f4f
--- /dev/null
+++ b/tests/errmsgs/twrong_explicit_typeargs.nim
@@ -0,0 +1,26 @@
+discard """
+  cmd: "nim c --hints:off -d:testsConciseTypeMismatch $file"
+  action: reject
+  nimout: '''
+twrong_explicit_typeargs.nim(26, 29) Error: type mismatch
+Expression: newImage[string](320, 200)
+  [1] 320: int literal(320)
+  [2] 200: int literal(200)
+
+Expected one of (first mismatch at [position]):
+[1] proc newImage[T: int32 | int64](w, h: int): ref Image[T]
+  generic parameter mismatch, expected int32 or int64 but got 'string' of type: string
+'''
+"""
+
+# bug #4084
+type
+  Image[T] = object
+    data: seq[T]
+
+proc newImage[T: int32|int64](w, h: int): ref Image[T] =
+  new(result)
+  result.data = newSeq[T](w * h)
+
+var correct = newImage[int32](320, 200)
+var wrong = newImage[string](320, 200)
diff --git a/tests/errmsgs/twrong_explicit_typeargs_legacy.nim b/tests/errmsgs/twrong_explicit_typeargs_legacy.nim
new file mode 100644
index 000000000..cfa528c54
--- /dev/null
+++ b/tests/errmsgs/twrong_explicit_typeargs_legacy.nim
@@ -0,0 +1,25 @@
+discard """
+  action: reject
+  nimout: '''
+twrong_explicit_typeargs_legacy.nim(25, 29) Error: type mismatch: got <int literal(320), int literal(200)>
+but expected one of:
+proc newImage[T: int32 | int64](w, h: int): ref Image[T]
+  first type mismatch at position: 1 in generic parameters
+  required type for T: int32 or int64
+  but expression 'string' is of type: string
+
+expression: newImage[string](320, 200)
+'''
+"""
+
+# bug #4084
+type
+  Image[T] = object
+    data: seq[T]
+
+proc newImage[T: int32|int64](w, h: int): ref Image[T] =
+  new(result)
+  result.data = newSeq[T](w * h)
+
+var correct = newImage[int32](320, 200)
+var wrong = newImage[string](320, 200)
diff --git a/tests/generics/mopensymimport1.nim b/tests/generics/mopensymimport1.nim
new file mode 100644
index 000000000..912db1302
--- /dev/null
+++ b/tests/generics/mopensymimport1.nim
@@ -0,0 +1,34 @@
+type
+  Result*[T, E] = object
+    when T is void:
+      when E is void:
+        oResultPrivate*: bool
+      else:
+        case oResultPrivate*: bool
+        of false:
+          eResultPrivate*: E
+        of true:
+          discard
+    else:
+      when E is void:
+        case oResultPrivate*: bool
+        of false:
+          discard
+        of true:
+          vResultPrivate*: T
+      else:
+        case oResultPrivate*: bool
+        of false:
+          eResultPrivate*: E
+        of true:
+          vResultPrivate*: T
+
+template valueOr*[T: not void, E](self: Result[T, E], def: untyped): untyped =
+  let s = (self) # TODO avoid copy
+  case s.oResultPrivate
+  of true:
+    s.vResultPrivate
+  of false:
+    when E isnot void:
+      template error: untyped {.used, inject.} = s.eResultPrivate
+    def
diff --git a/tests/generics/mopensymimport2.nim b/tests/generics/mopensymimport2.nim
new file mode 100644
index 000000000..c17aafd00
--- /dev/null
+++ b/tests/generics/mopensymimport2.nim
@@ -0,0 +1,16 @@
+{.experimental: "openSym".}
+
+import mopensymimport1
+
+type Xxx = enum
+  error
+  value
+
+proc f(): Result[int, cstring] =
+  Result[int, cstring](oResultPrivate: false, eResultPrivate: "f")
+
+proc g*(T: type): string =
+  let x = f().valueOr:
+    return $error
+
+  "ok"
diff --git a/tests/generics/t19848.nim b/tests/generics/t19848.nim
new file mode 100644
index 000000000..f80f0e298
--- /dev/null
+++ b/tests/generics/t19848.nim
@@ -0,0 +1,16 @@
+discard """
+  output: '''
+todo
+'''
+"""
+
+type
+  Maybe[T] = object
+  List[T] = object
+
+proc dump[M: Maybe](a: List[M]) =
+  echo "todo"
+
+var a: List[Maybe[int]]
+  
+dump(a)
diff --git a/tests/generics/t23790.nim b/tests/generics/t23790.nim
new file mode 100644
index 000000000..9ac0df6a1
--- /dev/null
+++ b/tests/generics/t23790.nim
@@ -0,0 +1,14 @@
+# bug #23790
+
+discard compiles($default(seq[seq[ref int]]))
+discard compiles($default(seq[seq[ref uint]]))
+discard compiles($default(seq[seq[ref int8]]))
+discard compiles($default(seq[seq[ref uint8]]))
+discard compiles($default(seq[seq[ref int16]]))
+discard compiles($default(seq[seq[ref uint16]]))
+discard compiles($default(seq[seq[ref int32]]))
+discard compiles($default(seq[seq[ref uint32]]))
+discard compiles($default(seq[seq[ref int64]]))
+discard compiles($default(seq[seq[ref uint64]]))
+proc s(_: int | string) = discard
+s(0)
diff --git a/tests/generics/t23853.nim b/tests/generics/t23853.nim
new file mode 100644
index 000000000..bc9514a53
--- /dev/null
+++ b/tests/generics/t23853.nim
@@ -0,0 +1,91 @@
+# issue #23853
+
+block simplified:
+  type QuadraticExt[F] = object
+    coords: array[2, F]
+  template Name(E: type QuadraticExt): int = 123
+  template getBigInt(Name: static int): untyped = int
+  type Foo[GT] = object
+    a: getBigInt(GT.Name)
+  var x: Foo[QuadraticExt[int]]
+  
+import std/macros
+
+type
+  Algebra* = enum
+    BN254_Snarks
+    BLS12_381
+
+  Fp*[Name: static Algebra] = object
+    limbs*: array[4, uint64]
+
+  QuadraticExt*[F] = object
+    ## Quadratic Extension field
+    coords*: array[2, F]
+
+  CubicExt*[F] = object
+    ## Cubic Extension field
+    coords*: array[3, F]
+
+  ExtensionField*[F] = QuadraticExt[F] or CubicExt[F]
+
+  Fp2*[Name: static Algebra] =
+    QuadraticExt[Fp[Name]]
+
+  Fp4*[Name: static Algebra] =
+    QuadraticExt[Fp2[Name]]
+
+  Fp6*[Name: static Algebra] =
+    CubicExt[Fp2[Name]]
+
+  Fp12*[Name: static Algebra] =
+    CubicExt[Fp4[Name]]
+    # QuadraticExt[Fp6[Name]]
+
+template Name*(E: type ExtensionField): Algebra =
+  E.F.Name
+
+const BLS12_381_Order = [uint64 0x1, 0x2, 0x3, 0x4]
+const BLS12_381_Modulus = [uint64 0x5, 0x6, 0x7, 0x8]
+
+
+{.experimental: "dynamicBindSym".}
+
+macro baseFieldModulus*(Name: static Algebra): untyped =
+  result = bindSym($Name & "_Modulus")
+
+macro scalarFieldModulus*(Name: static Algebra): untyped =
+  result = bindSym($Name & "_Order")
+
+type FieldKind* = enum
+  kBaseField
+  kScalarField
+
+template getBigInt*(Name: static Algebra, kind: static FieldKind): untyped =
+  # Workaround:
+  # in `ptr UncheckedArray[BigInt[EC.getScalarField().bits()]]
+  # EC.getScalarField is not accepted by the compiler
+  #
+  # and `ptr UncheckedArray[BigInt[Fr[EC.F.Name].bits]]` gets undeclared field: 'Name'
+  #
+  # but `ptr UncheckedArray[getBigInt(EC.getName(), kScalarField)]` works fine
+  when kind == kBaseField:
+    Name.baseFieldModulus().typeof()
+  else:
+    Name.scalarFieldModulus().typeof()
+
+# ------------------------------------------------------------------------------
+
+type BenchMultiexpContext*[GT] = object
+  elems: seq[GT]
+  exponents: seq[getBigInt(GT.Name, kScalarField)]
+
+proc createBenchMultiExpContext*(GT: typedesc, inputSizes: openArray[int]): BenchMultiexpContext[GT] =
+  discard
+
+# ------------------------------------------------------------------------------
+
+proc main() =
+  let ctx = createBenchMultiExpContext(Fp12[BLS12_381], [2, 4, 8, 16])
+
+main()
diff --git a/tests/generics/t23854.nim b/tests/generics/t23854.nim
new file mode 100644
index 000000000..f1175c8b2
--- /dev/null
+++ b/tests/generics/t23854.nim
@@ -0,0 +1,71 @@
+# issue #23854, not entirely fixed
+
+import std/bitops
+
+const WordBitWidth = sizeof(pointer) * 8
+
+func wordsRequired*(bits: int): int {.inline.} =
+  const divShiftor = fastLog2(uint32(WordBitWidth))
+  result = (bits + WordBitWidth - 1) shr divShiftor
+
+type
+  Algebra* = enum
+    BLS12_381
+
+  BigInt*[bits: static int] = object
+    limbs*: array[wordsRequired(bits), uint]
+
+  Fr*[Name: static Algebra] = object
+    residue_form*: BigInt[255]
+
+  Fp*[Name: static Algebra] = object
+    residue_form*: BigInt[381]
+
+  FF*[Name: static Algebra] = Fp[Name] or Fr[Name]
+
+template getBigInt*[Name: static Algebra](T: type FF[Name]): untyped =
+  ## Get the underlying BigInt type.
+  typeof(default(T).residue_form)
+
+type
+  EC_ShortW_Aff*[F] = object
+    ## Elliptic curve point for a curve in Short Weierstrass form
+    ##   y² = x³ + a x + b
+    ##
+    ## over a field F
+    x*, y*: F
+
+type FieldKind* = enum
+  kBaseField
+  kScalarField
+
+func bits*[Name: static Algebra](T: type FF[Name]): static int =
+  T.getBigInt().bits
+
+template getScalarField*(EC: type EC_ShortW_Aff): untyped =
+  Fr[EC.F.Name]
+
+# ------------------------------------------------------------------------------
+
+type
+  ECFFT_Descriptor*[EC] = object
+    ## Metadata for FFT on Elliptic Curve
+    order*: int
+    rootsOfUnity1*: ptr UncheckedArray[BigInt[EC.getScalarField().bits()]]  # Error: in expression 'EC.getScalarField()': identifier expected, but found 'EC.getScalarField'
+    rootsOfUnity2*: ptr UncheckedArray[BigInt[getScalarField(EC).bits()]] # Compiler SIGSEGV: Illegal Storage Access
+
+func new*(T: type ECFFT_Descriptor): T =
+  discard
+
+# ------------------------------------------------------------------------------
+
+template getBits[bits: static int](x: ptr UncheckedArray[BigInt[bits]]): int = bits
+
+proc main() =
+  let ctx = ECFFT_Descriptor[EC_ShortW_Aff[Fp[BLS12_381]]].new()
+  doAssert getBits(ctx.rootsOfUnity1) == 255
+  doAssert getBits(ctx.rootsOfUnity2) == 255
+  doAssert ctx.rootsOfUnity1[0].limbs.len == wordsRequired(255)
+  doAssert ctx.rootsOfUnity2[0].limbs.len == wordsRequired(255)
+
+main()
diff --git a/tests/generics/t23855.nim b/tests/generics/t23855.nim
new file mode 100644
index 000000000..da8135a98
--- /dev/null
+++ b/tests/generics/t23855.nim
@@ -0,0 +1,61 @@
+# issue #23855, not entirely fixed
+
+import std/bitops
+
+const WordBitWidth = sizeof(pointer) * 8
+
+func wordsRequired*(bits: int): int {.inline.} =
+  const divShiftor = fastLog2(uint32(WordBitWidth))
+  result = (bits + WordBitWidth - 1) shr divShiftor
+
+type
+  Algebra* = enum
+    BLS12_381
+
+  BigInt*[bits: static int] = object
+    limbs*: array[wordsRequired(bits), uint]
+
+  Fr*[Name: static Algebra] = object
+    residue_form*: BigInt[255]
+
+  Fp*[Name: static Algebra] = object
+    residue_form*: BigInt[381]
+
+  FF*[Name: static Algebra] = Fp[Name] or Fr[Name]
+
+template getBigInt*[Name: static Algebra](T: type FF[Name]): untyped =
+  ## Get the underlying BigInt type.
+  typeof(default(T).residue_form)
+
+type
+  EC_ShortW_Aff*[F] = object
+    ## Elliptic curve point for a curve in Short Weierstrass form
+    ##   y² = x³ + a x + b
+    ##
+    ## over a field F
+    x*, y*: F
+
+func bits*[Name: static Algebra](T: type FF[Name]): static int =
+  T.getBigInt().bits
+
+# ------------------------------------------------------------------------------
+
+type
+  ECFFT_Descriptor*[EC] = object
+    ## Metadata for FFT on Elliptic Curve
+    order*: int
+    rootsOfUnity*: ptr UncheckedArray[BigInt[Fr[EC.F.Name].bits()]] # Undeclared identifier `Name`
+
+func new*(T: type ECFFT_Descriptor): T =
+  discard
+
+# ------------------------------------------------------------------------------
+
+template getBits[bits: static int](x: ptr UncheckedArray[BigInt[bits]]): int = bits
+
+proc main() =
+  let ctx = ECFFT_Descriptor[EC_ShortW_Aff[Fp[BLS12_381]]].new()
+  doAssert getBits(ctx.rootsOfUnity) == 255
+  doAssert ctx.rootsOfUnity[0].limbs.len == wordsRequired(255)
+
+main()
diff --git a/tests/generics/taliashijack.nim b/tests/generics/taliashijack.nim
new file mode 100644
index 000000000..fdebadded
--- /dev/null
+++ b/tests/generics/taliashijack.nim
@@ -0,0 +1,8 @@
+# issue #23977
+
+type Foo[T] = int
+
+proc foo(T: typedesc) =
+  var a: T
+
+foo(int)
diff --git a/tests/generics/tbadcache.nim b/tests/generics/tbadcache.nim
new file mode 100644
index 000000000..33e65be3a
--- /dev/null
+++ b/tests/generics/tbadcache.nim
@@ -0,0 +1,26 @@
+# issue #16128
+
+import std/[tables, hashes]
+
+type
+  NodeId*[L] = object
+    isSource: bool
+    index: Table[NodeId[L], seq[NodeId[L]]]
+
+func hash*[L](id: NodeId[L]): Hash = discard
+func `==`[L](a, b: NodeId[L]): bool = discard
+
+proc makeIndex*[T, L](tree: T) =
+  var parent = NodeId[L]()
+  var tmp: Table[NodeId[L], seq[NodeId[L]]]
+  tmp[parent] = @[parent]
+
+proc simpleTreeDiff*[T, L](source, target: T) =
+  # Swapping these two lines makes error disappear
+  var m: Table[NodeId[L], NodeId[L]]
+  makeIndex[T, L](target)
+
+var tmp: Table[string, seq[string]] # removing this forward declaration also removes error
+
+proc diff(x1, x2: string): auto =
+  simpleTreeDiff[int, string](12, 12)
diff --git a/tests/generics/tbracketinstantiation.nim b/tests/generics/tbracketinstantiation.nim
new file mode 100644
index 000000000..22a86af4c
--- /dev/null
+++ b/tests/generics/tbracketinstantiation.nim
@@ -0,0 +1,86 @@
+discard """
+  nimout: '''
+type
+  Bob = object
+type
+  Another = object
+'''
+"""
+
+block: # issue #22645
+  type
+    Opt[T] = object
+    FutureBase = ref object of RootObj
+    Future[T] = ref object of FutureBase ## Typed future.
+      internalValue: T ## Stored value
+  template err[T](E: type Opt[T]): E = E()
+  proc works(): Future[Opt[int]] {.stackTrace: off, gcsafe, raises: [].} =
+    var chronosInternalRetFuture: FutureBase
+    template result(): untyped {.used.} =
+      Future[Opt[int]](chronosInternalRetFuture).internalValue
+    result = err(type(result))
+  proc breaks(): Future[Opt[int]] {.stackTrace: off, gcsafe, raises: [].} =
+    var chronosInternalRetFuture: FutureBase
+    template result(): untyped {.used.} =
+      cast[Future[Opt[int]]](chronosInternalRetFuture).internalValue
+    result = err(type(result))
+
+import macros
+
+block: # issue #16118
+  macro thing(name: static[string]) =
+    result = newStmtList(
+      nnkTypeSection.newTree(
+        nnkTypeDef.newTree(
+          ident(name),
+          newEmptyNode(),
+          nnkObjectTy.newTree(
+            newEmptyNode(),
+            newEmptyNode(),
+            nnkRecList.newTree()))))
+  template foo(name: string): untyped =
+    thing(name)
+  expandMacros:
+    foo("Bob")
+  block:
+    expandMacros:
+      foo("Another")
+
+block: # issue #19670
+  type
+    Past[Z] = object
+    OpenObject = object
+
+  macro rewriter(prc: untyped): untyped =
+    prc.body.add(nnkCall.newTree(
+      prc.params[0]
+    ))
+    prc
+    
+  macro macroAsync(name, restype: untyped): untyped =
+    quote do:
+      proc `name`(): Past[seq[`restype`]] {.rewriter.} = discard
+      
+  macroAsync(testMacro, OpenObject)
+
+import asyncdispatch
+
+block: # issue #11838 long
+  type
+    R[P] = object
+      updates: seq[P]
+    D[T, P] = ref object
+      ps: seq[P]
+      t: T
+  proc newD[T, P](ps: seq[P], t: T): D[T, P] =
+    D[T, P](ps: ps, t: t)
+  proc loop[T, P](d: D[T, P]) =
+    var results = newSeq[Future[R[P]]](10)
+  let d = newD[string, int](@[1], "")
+  d.loop()
+
+block: # issue #11838 minimal
+  type R[T] = object
+  proc loop[T]() =
+    discard newSeq[R[R[T]]]()
+  loop[int]()
diff --git a/tests/generics/tcalltype.nim b/tests/generics/tcalltype.nim
new file mode 100644
index 000000000..cba691f77
--- /dev/null
+++ b/tests/generics/tcalltype.nim
@@ -0,0 +1,26 @@
+discard """
+  joinable: false # breaks everything because of #23977
+"""
+
+# issue #23406
+
+template helper(_: untyped): untyped =
+  int
+
+type # Each of them should always be `int`.
+  GenA[T] = helper int
+  GenB[T] = helper(int)
+  GenC[T] = helper helper(int)
+
+block:
+  template helper(_: untyped): untyped =
+    float
+
+  type
+    A = GenA[int]
+    B = GenB[int]
+    C = GenC[int]
+
+  assert A is int # OK.
+  assert B is int # Fails; it is `float`!
+  assert C is int # OK.
diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim
index e0b61a58d..16a148f7b 100644
--- a/tests/generics/tgeneric0.nim
+++ b/tests/generics/tgeneric0.nim
@@ -186,3 +186,11 @@ block:
 
   var b: JsonValueRef[string]
   scanValue(b)
+
+block: # bug #21347
+  type K[T] = object
+  template s[T]() = discard
+  proc b1(n: bool | bool) = s[K[K[int]]]()
+  proc b2(n: bool) =        s[K[K[int]]]()
+  b1(false)   # Error: 's' has unspecified generic parameters
+  b2(false)   # Builds, on its own
diff --git a/tests/generics/tgenericwhen.nim b/tests/generics/tgenericwhen.nim
new file mode 100644
index 000000000..87672a699
--- /dev/null
+++ b/tests/generics/tgenericwhen.nim
@@ -0,0 +1,58 @@
+discard """
+  targets: "c js"
+"""
+
+block: # issue #24041
+  type ArrayBuf[N: static int, T = byte] = object
+    when sizeof(int) > sizeof(uint8):
+      when N <= int(uint8.high):
+        n: uint8
+      else:
+        when sizeof(int) > sizeof(uint16):
+          when N <= int(uint16.high):
+            n: uint16
+          else:
+            when sizeof(int) > sizeof(uint32):
+              when N <= int(uint32.high):
+                n: uint32
+              else:
+                n: int
+            else:
+              n: int
+        else:
+          n: int
+    else:
+      n: int
+
+  var x: ArrayBuf[8]
+  doAssert x.n is uint8
+  when sizeof(int) > sizeof(uint32):
+    var y: ArrayBuf[int(uint32.high) * 8]
+    doAssert y.n is int
+
+block: # constant condition after dynamic one
+  type Foo[T] = object
+    when T is int:
+      a: int
+    elif true:
+      a: string
+    else:
+      a: bool
+  var x: Foo[string]
+  doAssert x.a is string
+  var y: Foo[int]
+  doAssert y.a is int
+  var z: Foo[float]
+  doAssert z.a is string
+
+block: # issue #4774, but not with threads
+  const hasThreadSupport = not defined(js)
+  when hasThreadSupport:
+    type Channel[T] = object
+      value: T
+  type
+    SomeObj[T] = object
+      when hasThreadSupport:
+        channel: ptr Channel[T]
+  var x: SomeObj[int]
+  doAssert compiles(x.channel) == hasThreadSupport
diff --git a/tests/generics/tgensyminst.nim b/tests/generics/tgensyminst.nim
new file mode 100644
index 000000000..3f30188d8
--- /dev/null
+++ b/tests/generics/tgensyminst.nim
@@ -0,0 +1,29 @@
+# issue #24048
+
+import macros
+
+proc map(fn: proc(val: int): void) = fn(1)
+
+# This works fine, and is the exact same function call as what's
+# generated by the macro `aBug`.
+map proc(val: auto): void =
+  let variable = 123
+
+macro aBug() =
+  # 1. let sym = ident("variable")
+  let sym = genSym(nskLet, "variable")
+  let letStmt = newLetStmt(sym, newLit(123))
+
+  let lambda = newProc(
+    params = @[
+      ident("void"),
+      newIdentDefs(ident("val"), ident("auto")),
+      # 2. newIdentDefs(ident("val"), ident("int")),
+    ],
+    body = newStmtList(letStmt),
+    procType = nnkLambda
+  )
+
+  result = newCall(bindSym("map"), lambda)
+
+aBug()
diff --git a/tests/generics/timplicit_and_explicit.nim b/tests/generics/timplicit_and_explicit.nim
index ad0d1e88f..7220b7429 100644
--- a/tests/generics/timplicit_and_explicit.nim
+++ b/tests/generics/timplicit_and_explicit.nim
@@ -3,8 +3,8 @@ block: # basic test
   proc doStuff[T](a: SomeInteger): T = discard
   proc doStuff[T;Y](a: SomeInteger, b: Y): Y = discard
   assert typeof(doStuff[int](100)) is int
-  assert typeof(doStuff[int](100, 1.0)) is float
-  assert typeof(doStuff[int](100, "Hello")) is string
+  assert typeof(doStuff[int, float](100, 1.0)) is float
+  assert typeof(doStuff[int, string](100, "Hello")) is string
 
   proc t[T](x: T; z: int | float): seq[T] = result.add(x & $z)
 
diff --git a/tests/generics/tmacroinjectedsym.nim b/tests/generics/tmacroinjectedsym.nim
index d36d34cdd..985e415f2 100644
--- a/tests/generics/tmacroinjectedsym.nim
+++ b/tests/generics/tmacroinjectedsym.nim
@@ -1,4 +1,4 @@
-{.experimental: "genericsOpenSym".}
+{.experimental: "openSym".}
 
 block: # issue #22605, normal call syntax
   const error = "bad"
@@ -113,3 +113,74 @@ block: # issue #22605, original complex example
     "ok"
 
   doAssert g2(int) == "error"
+
+block: # issue #23865
+  type Xxx = enum
+    error
+    value
+
+  type
+    Result[T, E] = object
+      when T is void:
+        when E is void:
+          oResultPrivate: bool
+        else:
+          case oResultPrivate: bool
+          of false:
+            eResultPrivate: E
+          of true:
+            discard
+      else:
+        when E is void:
+          case oResultPrivate: bool
+          of false:
+            discard
+          of true:
+            vResultPrivate: T
+        else:
+          case oResultPrivate: bool
+          of false:
+            eResultPrivate: E
+          of true:
+            vResultPrivate: T
+
+  func error[T, E](self: Result[T, E]): E =
+    ## Fetch error of result if set, or raise Defect
+    case self.oResultPrivate
+    of true:
+      when T isnot void:
+        raiseResultDefect("Trying to access error when value is set", self.vResultPrivate)
+      else:
+        raiseResultDefect("Trying to access error when value is set")
+    of false:
+      when E isnot void:
+        self.eResultPrivate
+
+  template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped =
+    let s = (self) # TODO avoid copy
+    case s.oResultPrivate
+    of true:
+      s.vResultPrivate
+    of false:
+      when E isnot void:
+        template error: untyped {.used, inject.} = s.eResultPrivate
+      def
+  proc f(): Result[int, cstring] =
+    Result[int, cstring](oResultPrivate: false, eResultPrivate: "f")
+  proc g(T: type): string =
+    let x = f().valueOr:
+      return $error
+    "ok"
+  doAssert g(int) == "f"
+
+import sequtils
+
+block: # issue #12283
+  var b = 5
+  type Foo[T] = object
+    h, w: int
+  proc bar[T](foos: seq[Foo[T]]): T =
+    let w = foldl(foos, a + b.w, 0)
+    w
+  let foos = @[Foo[int](h: 3, w: 5), Foo[int](h: 4, w: 6)]
+  doAssert bar(foos) == 11
diff --git a/tests/generics/tmacroinjectedsymwarning.nim b/tests/generics/tmacroinjectedsymwarning.nim
index 7adb759e8..77119004b 100644
--- a/tests/generics/tmacroinjectedsymwarning.nim
+++ b/tests/generics/tmacroinjectedsymwarning.nim
@@ -1,3 +1,7 @@
+discard """
+  matrix: "--skipParentCfg --filenames:legacyRelProj"
+"""
+
 type Xxx = enum
   error
   value
@@ -42,8 +46,13 @@ proc f(): Result[int, cstring] =
 
 proc g(T: type): string =
   let x = f().valueOr:
+    {.push warningAsError[IgnoredSymbolInjection]: on.}
+    # test spurious error
+    discard true
+    let _ = f
+    {.pop.}
     return $error #[tt.Warning
-            ^ a new symbol 'error' has been injected during instantiation of g, however 'error' [enumField declared in tmacroinjectedsymwarning.nim(2, 3)] captured at the proc declaration will be used instead; either enable --experimental:genericsOpenSym to use the injected symbol or `bind` this captured symbol explicitly [GenericsIgnoredInjection]]#
+            ^ a new symbol 'error' has been injected during template or generic instantiation, however 'error' [enumField declared in tmacroinjectedsymwarning.nim(6, 3)] captured at the proc declaration will be used instead; either enable --experimental:openSym to use the injected symbol, or `bind` this captured symbol explicitly [IgnoredSymbolInjection]]#
 
   "ok"
 
diff --git a/tests/generics/tnestedissues.nim b/tests/generics/tnestedissues.nim
new file mode 100644
index 000000000..e96a1927e
--- /dev/null
+++ b/tests/generics/tnestedissues.nim
@@ -0,0 +1,24 @@
+block: # issue #23568
+  type G[T] = object
+    j: T
+  proc s[T](u: int) = discard
+  proc s[T]() = discard
+  proc c(e: int | int): G[G[G[int]]] = s[G[G[int]]]()
+  discard c(0)
+
+import std/options
+
+block: # issue #23310
+  type
+    BID = string or uint64
+    Future[T] = ref object of RootObj
+      internalValue: T
+    InternalRaisesFuture[T] = ref object of Future[T]
+  proc newInternalRaisesFutureImpl[T](): InternalRaisesFuture[T] =
+    let fut = InternalRaisesFuture[T]()
+  template newFuture[T](): auto =
+    newInternalRaisesFutureImpl[T]()
+  proc problematic(blockId: BID): Future[Option[seq[int]]] =
+    let resultFuture = newFuture[Option[seq[int]]]()
+    return resultFuture
+  let x = problematic("latest")
diff --git a/tests/generics/tnestedtemplate.nim b/tests/generics/tnestedtemplate.nim
new file mode 100644
index 000000000..22d0a2d3c
--- /dev/null
+++ b/tests/generics/tnestedtemplate.nim
@@ -0,0 +1,9 @@
+block: # issue #13979
+  var s: seq[int]
+  proc filterScanline[T](input: openArray[T]) =
+    template currPix: untyped = input[i]
+    for i in 0..<input.len:
+      s.add currPix
+  let pix = [1, 2, 3]
+  filterScanline(pix)
+  doAssert s == @[1, 2, 3]
diff --git a/tests/generics/topensymimport.nim b/tests/generics/topensymimport.nim
new file mode 100644
index 000000000..a47496827
--- /dev/null
+++ b/tests/generics/topensymimport.nim
@@ -0,0 +1,5 @@
+# issue #23386
+
+import mopensymimport2
+
+doAssert g(int) == "f"
diff --git a/tests/generics/tstatic_constrained.nim b/tests/generics/tstatic_constrained.nim
index 3c9201548..d356b9d1c 100644
--- a/tests/generics/tstatic_constrained.nim
+++ b/tests/generics/tstatic_constrained.nim
@@ -8,7 +8,7 @@ but expected: <T: float or string, Y>
 tstatic_constrained.nim(44, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)]
 got: <typedesc[int], int literal(10)>
 but expected: <T: float or string, Y>
-tstatic_constrained.nim(44, 31) Error: object constructor needs an object type [proxy]
+tstatic_constrained.nim(44, 31) Error: object constructor needs an object type [error]
 tstatic_constrained.nim(44, 31) Error: expression '' has no type (or is ambiguous)
 tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)]
 got: <typedesc[byte], uint8>
@@ -16,7 +16,7 @@ but expected: <T: float or string, Y>
 tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)]
 got: <typedesc[byte], uint8>
 but expected: <T: float or string, Y>
-tstatic_constrained.nim(45, 34) Error: object constructor needs an object type [proxy]
+tstatic_constrained.nim(45, 34) Error: object constructor needs an object type [error]
 tstatic_constrained.nim(45, 34) Error: expression '' has no type (or is ambiguous)
 tstatic_constrained.nim(77, 14) Error: cannot instantiate MyType [type declared in tstatic_constrained.nim(71, 5)]
 got: <typedesc[float], float64>
@@ -76,4 +76,4 @@ block:
     b: MyType[string, "hello"]
     c: MyType[float, 10d]
     d: MyOtherType[MyOtherConstraint[float],MyOtherConstraint[float]()]
-    e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()]
\ No newline at end of file
+    e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()]
diff --git a/tests/generics/tuninstantiatedgenericcalls.nim b/tests/generics/tuninstantiatedgenericcalls.nim
index bac334e95..f33fc8967 100644
--- a/tests/generics/tuninstantiatedgenericcalls.nim
+++ b/tests/generics/tuninstantiatedgenericcalls.nim
@@ -140,3 +140,378 @@ block: # issue #1771
 
   var a: Foo[range[0..2], float]
   doAssert test(a) == 0.0
+
+block: # issue #23730
+  proc test(M: static[int]): array[1 shl M, int] = discard
+  doAssert len(test(3)) == 8
+  doAssert len(test(5)) == 32
+
+block: # issue #19819
+  type
+    Example[N: static int] = distinct int
+    What[E: Example] = Example[E.N + E.N]
+
+block: # issue #23339
+  type
+    A = object
+    B = object
+  template aToB(t: typedesc[A]): typedesc = B
+  type
+    Inner[I] = object
+      innerField: I
+    Outer[O] = object
+      outerField: Inner[O.aToB]
+  var x: Outer[A]
+  doAssert typeof(x.outerField.innerField) is B
+
+block: # deref syntax
+  type
+    Enqueueable = concept x
+      x is ptr
+    Foo[T: Enqueueable] = object
+      x: typeof(default(T)[])
+
+  proc p[T](f: Foo[T]) =
+    var bar: Foo[T]
+    discard
+  var foo: Foo[ptr int]
+  p(foo)
+  doAssert foo.x is int
+  foo.x = 123
+  doAssert foo.x == 123
+  inc foo.x
+  doAssert foo.x == 124
+
+block:
+  type Generic[T] = object
+    field: T
+  macro foo(x: typed): untyped = x
+  macro bar[T](x: typedesc[Generic[T]]): untyped = x
+  type
+    Foo[T] = object
+      field: Generic[int].foo()
+    Foo2[T] = object
+      field: Generic[T].foo()
+    Bar[T] = object
+      field: Generic[int].bar()
+    Bar2[T] = object
+      field: Generic[T].bar()
+  var x: Foo[int]
+  var x2: Foo2[int]
+  var y: Bar[int]
+  var y2: Bar2[int]
+
+block:
+  macro pick(x: static int): untyped =
+    if x < 100:
+      result = bindSym"int"
+    else:
+      result = bindSym"float"
+  
+  type Foo[T: static int] = object
+    fixed1: pick(25)
+    fixed2: pick(125)
+    unknown: pick(T)
+  
+  var a: Foo[123]
+  doAssert a.fixed1 is int
+  doAssert a.fixed2 is float
+  doAssert a.unknown is float
+  var b: Foo[23]
+  doAssert b.fixed1 is int
+  doAssert b.fixed2 is float
+  doAssert b.unknown is int
+
+import std/sequtils
+
+block: # version of #23432 with `typed`, don't delay instantiation
+  type
+    Future[T] = object
+    InternalRaisesFuture[T, E] = object
+  macro Raising[T](F: typedesc[Future[T]], E: varargs[typed]): untyped =
+    let raises = nnkTupleConstr.newTree(E.mapIt(it))
+    nnkBracketExpr.newTree(
+      ident "InternalRaisesFuture",
+      nnkDotExpr.newTree(F, ident"T"),
+      raises
+    )
+  type X[E] = Future[void].Raising(E)
+  proc f(x: X) = discard
+  var v: Future[void].Raising([ValueError])
+  f(v)
+
+block: # issue #22647
+  proc c0(n: static int): int = 8
+  proc c1(n: static int): int = n div 2
+  proc c2(n: static int): int = n * 2
+  proc c3(n: static int, n2: int): int = n * n2
+  proc `**`(n: static int, n2: int): int = n * n2
+  proc c4(n: int, n2: int): int = n * n2
+
+  type
+    a[N: static int] = object
+      f0 : array[N, int]
+
+    b[N: static int] = object
+      f0 : a[c0(N)]  # does not work
+      f1 : a[c1(N)]  # does not work
+      f2 : a[c2(N)]  # does not work
+      f3 : a[N * 2]  # does not work
+      f4 : a[N]      # works
+      f5: a[c3(N, 2)]
+      f6: a[N ** 2]
+      f7: a[2 * N]
+      f8: a[c4(N, 2)]
+
+  proc p[N: static int](x : a[N]) = discard x.f0[0]
+  template check(x, s: untyped) =
+    p(x)
+    doAssert x is a[s]
+    doAssert x.N == s
+    doAssert typeof(x).N == s
+    doAssert x.f0 == default(array[s, int])
+    doAssert x.f0.len == s
+    proc p2[N: static int](y : a[N]) {.gensym.} =
+      doAssert y is a[s]
+      doAssert y.N == s
+      doAssert typeof(y).N == s
+      doAssert y.f0 == default(array[s, int])
+      doAssert y.f0.len == s
+    p2(x)
+    proc p3(z: typeof(x)) {.gensym.} = discard
+    p3(default(a[s]))
+  proc p[N: static int](x : b[N]) =
+    x.f0.check(8)
+    x.f1.check(2)
+    x.f2.check(8)
+    x.f3.check(8)
+    x.f4.check(4)
+    x.f5.check(8)
+    x.f6.check(8)
+    x.f7.check(8)
+    x.f8.check(8)
+
+  var x: b[4]
+  x.p()
+
+block: # issue #1969
+  type ZeroGenerator = object
+  proc next(g: ZeroGenerator): int = 0
+  # This compiles.
+  type TripleOfInts = tuple
+    a, b, c: typeof(new(ZeroGenerator)[].next)
+  # This raises a compiler error before it's even instantiated.
+  # The `new` proc can't be resolved because `Generator` is not defined.
+  type TripleLike[Generator] = tuple
+    a, b, c: typeof(new(Generator)[].next)
+
+import std/atomics
+
+block: # issue #12720
+  const CacheLineSize = 128
+  type
+    Enqueueable = concept x, type T
+      x is ptr
+      x.next is Atomic[pointer]
+    MyChannel[T: Enqueueable] = object
+      pad: array[CacheLineSize - sizeof(default(T)[]), byte]
+      dummy: typeof(default(T)[])
+
+block: # issue #12714
+  type
+    Enqueueable = concept x, type T
+      x is ptr
+      x.next is Atomic[pointer]
+    MyChannel[T: Enqueueable] = object
+      dummy: type(default(T)[])
+
+block: # issue #24044
+  type ArrayBuf[N: static int, T = byte] = object
+    buf: array[N, T]
+  template maxLen(T: type): int =
+    sizeof(T) * 2
+  type MyBuf[I] = ArrayBuf[maxLen(I)]
+  var v: MyBuf[int]
+
+block: # issue #15959
+  proc my[T](a: T): typeof(a[0]) = discard
+  proc my2[T](a: T): array[sizeof(a[0]), T] = discard
+  proc byLent2[T](a: T): lent type(a[0]) = a[0] # Error: type mismatch: got <T, int literal(0)>
+  proc byLent3[T](a: T): lent typeof(a[0]) = a[0] # ditto
+  proc byLent4[T](a: T): lent[type(a[0])] = a[0] # Error: no generic parameters allowed for lent
+  var x = @[1, 2, 3]
+  doAssert my(x) is int
+  doAssert my2(x) is array[sizeof(int), seq[int]]
+  doAssert byLent2(x) == 1
+  doAssert byLent2(x) is lent int
+  doAssert byLent3(x) == 1
+  doAssert byLent3(x) is lent int
+  doAssert byLent4(x) == 1
+  doAssert byLent4(x) is lent int
+  proc fn[U](a: U): auto = a
+  proc my3[T](a: T, b: typeof(fn(a))) = discard
+  my3(x, x)
+  doAssert not compiles(my3(x, x[0]))
+
+block: # issue #22342, type section version of #22607
+  type GenAlias[isInt: static bool] = (
+    when isInt:
+      int
+    else:
+      float
+  )
+  doAssert GenAlias[true] is int
+  doAssert GenAlias[false] is float
+  proc foo(T: static bool): GenAlias[T] = discard
+  doAssert foo(true) is int
+  doAssert foo(false) is float
+  proc foo[T: static bool](v: var GenAlias[T]) =
+    v += 1
+  var x: int
+  foo[true](x)
+  doAssert not compiles(foo[false](x))
+  foo[true](x)
+  doAssert x == 2
+  var y: float
+  foo[false](y)
+  doAssert not compiles(foo[true](y))
+  foo[false](y)
+  doAssert y == 2
+
+block: # `when`, test no constant semchecks
+  type Foo[T] = (
+    when false:
+      {.error: "bad".}
+    elif defined(neverDefined):
+      {.error: "bad 2".}
+    else:
+      T
+  )
+  var x: Foo[int]
+  type Bar[T] = (
+    when true:
+      T
+    elif defined(js):
+      {.error: "bad".}
+    else:
+      {.error: "bad 2".}
+  )
+  var y: Bar[int]
+
+block: # weird regression
+  type
+    Foo[T] = distinct int
+    Bar[T, U] = distinct int
+  proc foo[T, U](x: static Foo[T], y: static Bar[T, U]): Foo[T] =
+    # signature gives:
+    # Error: cannot instantiate Bar
+    # got: <typedesc[T], U>
+    # but expected: <T, U>
+    x
+  doAssert foo(Foo[int](1), Bar[int, int](2)).int == 1
+
+block: # issue #24090
+  type M[V] = object
+  template y[V](N: type M, v: V): M[V] = default(M[V])
+  proc d(x: int | int, f: M[int] = M.y(0)) = discard
+  d(0, M.y(0))
+  type Foo[T] = object
+    x: typeof(M.y(default(T)))
+  var a: Foo[int]
+  doAssert a.x is M[int]
+  var b: Foo[float]
+  doAssert b.x is M[float]
+  doAssert not (compiles do:
+    type Bar[T] = object
+      x: typeof(M()) # actually fails here immediately
+    var bar: Bar[int])
+  doAssert not (compiles do:
+    type Bar[T] = object
+      x: typeof(default(M))
+    var bar: Bar[int]
+    # gives "undeclared identifier x" because of #24091,
+    # normally it should fail in the line above
+    echo bar.x)
+  proc foo[T: M](x: T = default(T)) = discard x
+  foo[M[int]]()
+  doAssert not compiles(foo())
+
+block: # above but encountered by sigmatch using replaceTypeVarsN
+  type Opt[T] = object
+    x: T
+  proc none[T](x: type Opt, y: typedesc[T]): Opt[T] = discard
+  proc foo[T](x: T, a = Opt.none(int)) = discard
+  foo(1, a = Opt.none(int))
+  foo(1)
+
+block: # real version of above
+  type Opt[T] = object
+    x: T
+  template none(x: type Opt, T: type): Opt[T] = Opt[T]()
+  proc foo[T](x: T, a = Opt.none(int)) = discard
+  foo(1, a = Opt.none(int))
+  foo(1)
+
+block: # issue #20880
+  type
+    Child[n: static int] = object
+      data: array[n, int]
+    Parent[n: static int] = object
+      child: Child[3*n]
+  const n = 3
+  doAssert $(typeof Parent[n*3]()) == "Parent[9]"
+  doAssert $(typeof Parent[1]().child) == "Child[3]"
+  doAssert Parent[1]().child.data.len == 3
+
+{.experimental: "dynamicBindSym".}
+block: # issue #16774
+  type SecretWord = distinct uint64
+  const WordBitWidth = 8 * sizeof(uint64)
+  func wordsRequired(bits: int): int {.compileTime.} =
+    ## Compute the number of limbs required
+    # from the **announced** bit length
+    (bits + WordBitWidth - 1) div WordBitWidth
+  type
+    Curve = enum BLS12_381
+    BigInt[bits: static int] = object
+      limbs: array[bits.wordsRequired, SecretWord]
+  const BLS12_381_Modulus = default(BigInt[381])
+  macro Mod(C: static Curve): untyped =
+    ## Get the Modulus associated to a curve
+    result = bindSym($C & "_Modulus")
+  macro getCurveBitwidth(C: static Curve): untyped =
+    result = nnkDotExpr.newTree(
+      getAST(Mod(C)),
+      ident"bits"
+    )
+  type Fp[C: static Curve] = object
+    ## Finite Fields / Modular arithmetic
+    ## modulo the curve modulus
+    mres: BigInt[getCurveBitwidth(C)]
+  var x: Fp[BLS12_381]
+  doAssert x.mres.limbs.len == wordsRequired(getCurveBitWidth(BLS12_381))
+  # minimized, as if we haven't tested it already:
+  macro makeIntLit(c: static int): untyped =
+    result = newLit(c)
+  type Test[T: static int] = object
+    myArray: array[makeIntLit(T), int]
+  var y: Test[2]
+  doAssert y.myArray.len == 2
+  var z: Test[4]
+  doAssert z.myArray.len == 4
+
+block: # issue #16175
+  type
+    Thing[D: static uint] = object
+      when D == 0:
+        kid: char
+      else:
+        kid: Thing[D-1]
+  var t2 = Thing[3]()
+  doAssert t2.kid is Thing[2.uint]
+  doAssert t2.kid.kid is Thing[1.uint]
+  doAssert t2.kid.kid.kid is Thing[0.uint]
+  doAssert t2.kid.kid.kid.kid is char
+  var s = Thing[1]()
+  doAssert s.kid is Thing[0.uint]
+  doAssert s.kid.kid is char
diff --git a/tests/generics/twrong_explicit_typeargs.nim b/tests/generics/twrong_explicit_typeargs.nim
deleted file mode 100644
index e47b38e99..000000000
--- a/tests/generics/twrong_explicit_typeargs.nim
+++ /dev/null
@@ -1,16 +0,0 @@
-discard """
-  errormsg: "cannot instantiate: 'newImage[string]'"
-  line: 16
-"""
-
-# bug #4084
-type
-  Image[T] = object
-    data: seq[T]
-
-proc newImage[T: int32|int64](w, h: int): ref Image[T] =
-  new(result)
-  result.data = newSeq[T](w * h)
-
-var correct = newImage[int32](320, 200)
-var wrong = newImage[string](320, 200)
diff --git a/tests/generics/twrong_generic_object.nim b/tests/generics/twrong_generic_object.nim
index 442b89ea1..4951f735f 100644
--- a/tests/generics/twrong_generic_object.nim
+++ b/tests/generics/twrong_generic_object.nim
@@ -1,6 +1,6 @@
 discard """
-  errormsg: "cannot instantiate: 'GenericNodeObj[T]'; Maybe generic arguments are missing?"
-  line: 21
+  errormsg: "'Node' is not a concrete type"
+  line: 11
 """
 # bug #2509
 type
diff --git a/tests/int/t1.nim b/tests/int/t1.nim
index 36402da07..6e5cdc8d4 100644
--- a/tests/int/t1.nim
+++ b/tests/int/t1.nim
@@ -1,3 +1,7 @@
+discard """
+  targets: "c cpp"
+"""
+
 doAssert typeOf(1.int64 + 1.int) is int64
 doAssert typeOf(1.uint64 + 1.uint) is uint64
 doAssert int64 is SomeNumber
@@ -12,3 +16,46 @@ doAssert typeOf(myInt16 + myInt) is int   # of type `int`
 doAssert typeOf(myInt16 + 2i32) is int32  # of type `int32`
 doAssert int32 isnot int64
 doAssert int32 isnot int
+
+block: # bug #23947
+  template foo =
+    let test_u64 : uint64 =   0xFF07.uint64
+    let test_u8  : uint8  = test_u64.uint8
+        # Error: illegal conversion from '65287' to '[0..255]'
+    doAssert test_u8 == 7
+
+  static: foo()
+  foo()
+
+block:
+  # bug #22085
+  const
+    x = uint32(uint64.high) # vm error
+    u = uint64.high
+    v = uint32(u) # vm error
+
+  let
+    z = uint64.high
+    y = uint32(z)  # runtime ok
+
+  let
+    w = uint32(uint64.high)  # semfold error
+
+  doAssert x == w
+  doAssert v == y
+
+  # bug #14522
+  doAssert 0xFF000000_00000000.uint64 == 18374686479671623680'u64
+
+block: # bug #23954
+  let testRT_u8 : uint8 = 0x107.uint8
+  doAssert testRT_u8 == 7
+  const testCT_u8 : uint8 = 0x107.uint8
+  doAssert testCT_u8 == 7
+
+block: # issue #24104
+  type P = distinct uint  # uint, uint8, uint16, uint32, uint64 
+  let v = 0.P
+  case v
+  of 0.P: discard
+  else:   discard
diff --git a/tests/int/tints.nim b/tests/int/tints.nim
index 5c071c21d..773e8ccad 100644
--- a/tests/int/tints.nim
+++ b/tests/int/tints.nim
@@ -1,6 +1,5 @@
 discard """
-  matrix: "; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on"
-  targets: "c js"
+  matrix: "; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
   output: '''
 0 0
 0 0
@@ -8,7 +7,6 @@ Success'''
 """
 # Test the different integer operations
 
-# TODO: fixme --backend:js cannot change targets!!!
 
 import std/private/jsutils
 
diff --git a/tests/int/tunsignedinc.nim b/tests/int/tunsignedinc.nim
index 9d1a4bbb4..9392f1b74 100644
--- a/tests/int/tunsignedinc.nim
+++ b/tests/int/tunsignedinc.nim
@@ -32,3 +32,9 @@ block t4175:
   const j = 0u - 1u
   doAssert i == j
   doAssert j + 1u == 0u
+
+block: # https://forum.nim-lang.org/t/12465#76998
+  var a: int = 1
+  var x: uint8 = 1
+  a.inc(x)   # Error: type mismatch
+  doAssert a == 2
diff --git a/tests/int/twrongexplicitvarconv.nim b/tests/int/twrongexplicitvarconv.nim
new file mode 100644
index 000000000..79f770e8e
--- /dev/null
+++ b/tests/int/twrongexplicitvarconv.nim
@@ -0,0 +1,16 @@
+discard """
+  action: reject
+  nimout: '''
+  but expression 'int(a)' is immutable, not 'var'
+'''
+"""
+
+proc `++`(n: var int) =
+  n += 1
+
+var a: int32 = 15
+
+++int(a) #[tt.Error
+^ type mismatch: got <int>]#
+
+echo a
diff --git a/tests/int/twrongvarconv.nim b/tests/int/twrongvarconv.nim
new file mode 100644
index 000000000..db6ac2c53
--- /dev/null
+++ b/tests/int/twrongvarconv.nim
@@ -0,0 +1,9 @@
+proc `++`(n: var int) =
+  n += 1
+
+var a: int32 = 15
+
+++a #[tt.Error
+^ type mismatch: got <int32>]#
+
+echo a
diff --git a/tests/iter/t1550.nim b/tests/iter/t1550.nim
index 8ad96f0da..c971943ee 100644
--- a/tests/iter/t1550.nim
+++ b/tests/iter/t1550.nim
@@ -1,3 +1,7 @@
+discard """
+  targets: "c js"
+"""
+
 type
   A[T] = iterator(x: T): T {.gcsafe, closure.}
 
diff --git a/tests/iter/t21306.nim b/tests/iter/t21306.nim
index 43fea9c80..4d0396294 100644
--- a/tests/iter/t21306.nim
+++ b/tests/iter/t21306.nim
@@ -1,3 +1,7 @@
+discard """
+  targets: "c js"
+"""
+
 # bug #21306
 type
   FutureState {.pure.} = enum
diff --git a/tests/iter/t2771.nim b/tests/iter/t2771.nim
index 49befb0a9..71a8a9dcd 100644
--- a/tests/iter/t2771.nim
+++ b/tests/iter/t2771.nim
@@ -1,3 +1,7 @@
+discard """
+  targets: "c js"
+"""
+
 template t1(i: int): int=
   i+1
 template t2(i: int): int=
diff --git a/tests/iter/tanoniter1.nim b/tests/iter/tanoniter1.nim
index 9f0d0a74b..fee16497f 100644
--- a/tests/iter/tanoniter1.nim
+++ b/tests/iter/tanoniter1.nim
@@ -1,4 +1,5 @@
 discard """
+  targets: "c js"
   output: '''1
 2
 3
diff --git a/tests/iter/tclosureiters.nim b/tests/iter/tclosureiters.nim
index 85611373c..4a2639852 100644
--- a/tests/iter/tclosureiters.nim
+++ b/tests/iter/tclosureiters.nim
@@ -1,4 +1,5 @@
 discard """
+  targets: "c js"
   output: '''0
 1
 2
@@ -152,15 +153,18 @@ iterator filesIt(path: string): auto {.closure.} =
       yield prefix / f
 
 # bug #13815
-var love = iterator: int {.closure.} =
-  yield cast[type(
-    block:
-      var a = 0
-      yield a
-      a)](0)
-
-for i in love():
-  echo i
+when not defined(js):
+  var love = iterator: int {.closure.} =
+    yield cast[type(
+      block:
+        var a = 0
+        yield a
+        a)](0)
+
+  for i in love():
+    echo i
+else:
+  echo 0
 
 # bug #18474
 iterator pairs(): (int, int) {.closure.} =
diff --git a/tests/iter/titer11.nim b/tests/iter/titer11.nim
index 2b39c74f7..153b3c29a 100644
--- a/tests/iter/titer11.nim
+++ b/tests/iter/titer11.nim
@@ -1,4 +1,5 @@
 discard """
+targets: "c js"
 output: '''
 [
 1
diff --git a/tests/iter/titer12.nim b/tests/iter/titer12.nim
index f7fc64da4..f264a0e82 100644
--- a/tests/iter/titer12.nim
+++ b/tests/iter/titer12.nim
@@ -1,4 +1,5 @@
 discard """
+targets: "c js"
 output: '''
 Selecting 2
 1.0
diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim
index adba8a8e3..c82b3902d 100644
--- a/tests/iter/titer_issues.nim
+++ b/tests/iter/titer_issues.nim
@@ -1,4 +1,5 @@
 discard """
+  target: "c js"
   output: '''
 0
 1
@@ -392,3 +393,19 @@ iterator tryFinally() {.closure.} =
 
 var x = tryFinally
 x()
+
+block: # bug #24033
+  type Query = ref object
+
+  iterator pairs(query: Query): (int, (string, float32)) =
+    var output: (int, (string, float32)) = (0, ("foo", 3.14))
+    for id in @[0, 1, 2]:
+      output[0] = id
+      yield output
+
+  var collections: seq[(int, string, string)]
+
+  for id, (str, num) in Query():
+    collections.add (id, str, $num)
+
+  doAssert collections[1] == (1, "foo", "3.14")
diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim
index 47ba6efa6..e51ab7f0d 100644
--- a/tests/iter/tyieldintry.nim
+++ b/tests/iter/tyieldintry.nim
@@ -1,5 +1,5 @@
 discard """
-  matrix: "; --experimental:strictdefs"
+  matrix: "; --experimental:strictdefs; -d:nimOptIters"
   targets: "c cpp"
 """
 
@@ -504,3 +504,26 @@ block: # void iterator
     except:
       discard
   var a = it
+
+if defined(nimOptIters): # Locals present in only 1 state should be on the stack
+  proc checkOnStack(a: pointer, shouldBeOnStack: bool) =
+    # Quick and dirty way to check if a points to stack
+    var dummy = 0
+    let dummyAddr = addr dummy
+    let distance = abs(cast[int](dummyAddr) - cast[int](a))
+    const requiredDistance = 300
+    if shouldBeOnStack:
+      doAssert(distance <= requiredDistance, "a is not on stack, but should")
+    else:
+      doAssert(distance > requiredDistance, "a is on stack, but should not")
+
+  iterator it(): int {.closure.} =
+    var a = 1
+    var b = 2
+    var c {.liftLocals.} = 3
+    checkOnStack(addr a, true)
+    checkOnStack(addr b, false)
+    checkOnStack(addr c, false)
+    yield a
+    yield b
+  test(it, 1, 2)
diff --git a/tests/js/t7109.nim b/tests/js/t7109.nim
index 015d11d87..a1a3b718e 100644
--- a/tests/js/t7109.nim
+++ b/tests/js/t7109.nim
@@ -3,3 +3,6 @@ iterator iter*(): int {.closure.} =
 
 var x = iter
 doAssert x() == 3
+
+let fIt = iterator(): int = yield 70
+doAssert fIt() == 70
diff --git a/tests/js/tdanger.nim b/tests/js/tdanger.nim
new file mode 100644
index 000000000..9088859a8
--- /dev/null
+++ b/tests/js/tdanger.nim
@@ -0,0 +1,17 @@
+discard """
+  matrix: ";--d:danger"
+"""
+
+block:
+  proc foo() =
+    var name = int64(12)
+    var x = uint32(name)
+    var m = x + 12
+
+    var y = int32(name)
+    var n = y + 1
+
+    doAssert m == uint32(n + 11)
+
+
+  foo()
diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim
index 265ae52e9..f27ea5546 100644
--- a/tests/js/tjsffi.nim
+++ b/tests/js/tjsffi.nim
@@ -1,4 +1,5 @@
 discard """
+matrix: "--legacy:jsnolambdalifting;"
 output: '''
 3
 2
diff --git a/tests/js/tjsnimscombined.nim b/tests/js/tjsnimscombined.nim
new file mode 100644
index 000000000..4d3e6c453
--- /dev/null
+++ b/tests/js/tjsnimscombined.nim
@@ -0,0 +1 @@
+import std/jsffi
diff --git a/tests/js/tjsnimscombined.nims b/tests/js/tjsnimscombined.nims
new file mode 100644
index 000000000..01b93d3fa
--- /dev/null
+++ b/tests/js/tjsnimscombined.nims
@@ -0,0 +1 @@
+# test the condition where both `js` and `nimscript` are defined (nimscript receives priority)
diff --git a/tests/js/ttypedarray.nim b/tests/js/ttypedarray.nim
index 08b5fcdde..4807cb103 100644
--- a/tests/js/ttypedarray.nim
+++ b/tests/js/ttypedarray.nim
@@ -1,5 +1,5 @@
 discard """
-  matrix: "--jsbigint64:off; --jsbigint64:on"
+  matrix: "--jsbigint64:off -d:nimStringHash2; --jsbigint64:on"
 """
 
 import std/private/jsutils
diff --git a/tests/lent/tlent_from_var.nim b/tests/lent/tlent_from_var.nim
index d61ff6dc0..1fb3d0c17 100644
--- a/tests/lent/tlent_from_var.nim
+++ b/tests/lent/tlent_from_var.nim
@@ -50,3 +50,58 @@ template get*[T: not void](self: Opt[T]): T = self.value()
 method connect*(
   self: Opt[(int, int)]) =
   discard self.get()[0]
+
+block: # bug #23454
+  type
+    Letter = enum
+      A
+
+    LetterPairs = object
+      values: seq[(Letter, string)]
+
+  iterator items(list: var LetterPairs): lent (Letter, string) =
+    for item in list.values:
+      yield item
+
+  var instance = LetterPairs(values: @[(A, "foo")])
+
+  for (a, _) in instance:
+    case a
+    of A: discard
+
+block: # bug #23454
+  type
+    Letter = enum
+      A
+
+    LetterPairs = object
+      values: seq[(Letter, string)]
+
+  iterator items(list: var LetterPairs): var (Letter, string) =
+    for item in list.values.mItems:
+      yield item
+
+  var instance = LetterPairs(values: @[(A, "foo")])
+
+  for (a, _) in instance:
+    case a
+    of A: discard
+
+block: # bug #24034
+  type T = object
+    v: array[100, byte]
+
+
+  iterator pairs(t: T): (int, lent array[100, byte]) =
+    yield (0, t.v)
+
+
+  block:
+    for a, b in default(T):
+      doAssert a == 0
+      doAssert b.len == 100
+
+  block:
+    for (a, b) in pairs(default(T)):
+      doAssert a == 0
+      doAssert b.len == 100
diff --git a/tests/lent/tvm.nim b/tests/lent/tvm.nim
new file mode 100644
index 000000000..5df1d1270
--- /dev/null
+++ b/tests/lent/tvm.nim
@@ -0,0 +1,21 @@
+block: # issue #17527
+  iterator items2[IX, T](a: array[IX, T]): lent T {.inline.} =
+    var i = low(IX)
+    if i <= high(IX):
+      while true:
+        yield a[i]
+        if i >= high(IX): break
+        inc(i)
+
+  proc main() =
+    var s: seq[string] = @[]
+    for i in 0..<3:
+      for (key, val) in items2([("any", "bar")]):
+        s.add $(i, key, val)
+    doAssert s == @[
+      "(0, \"any\", \"bar\")",
+      "(1, \"any\", \"bar\")",
+      "(2, \"any\", \"bar\")"
+    ]
+
+  static: main()
diff --git a/tests/lookups/mambtype1.nim b/tests/lookups/mambtype1.nim
new file mode 100644
index 000000000..47046142e
--- /dev/null
+++ b/tests/lookups/mambtype1.nim
@@ -0,0 +1 @@
+type K* = object
diff --git a/tests/lookups/mambtype2.nim b/tests/lookups/mambtype2.nim
new file mode 100644
index 000000000..cf622466b
--- /dev/null
+++ b/tests/lookups/mambtype2.nim
@@ -0,0 +1,4 @@
+import ./mambtype1
+export mambtype1
+template K*(kind: static int): auto = typedesc[mambtype1.K]
+template B*(kind: static int): auto = typedesc[mambtype1.K]
diff --git a/tests/lookups/mdisambsym1.nim b/tests/lookups/mdisambsym1.nim
new file mode 100644
index 000000000..b8beca035
--- /dev/null
+++ b/tests/lookups/mdisambsym1.nim
@@ -0,0 +1,2 @@
+proc count*(s: string): int = 
+  s.len
diff --git a/tests/lookups/mdisambsym2.nim b/tests/lookups/mdisambsym2.nim
new file mode 100644
index 000000000..1e056311d
--- /dev/null
+++ b/tests/lookups/mdisambsym2.nim
@@ -0,0 +1 @@
+var count*: int = 10
diff --git a/tests/lookups/mdisambsym3.nim b/tests/lookups/mdisambsym3.nim
new file mode 100644
index 000000000..95bd19702
--- /dev/null
+++ b/tests/lookups/mdisambsym3.nim
@@ -0,0 +1 @@
+const count* = 3.142
diff --git a/tests/lookups/mmacroamb.nim b/tests/lookups/mmacroamb.nim
new file mode 100644
index 000000000..107e51055
--- /dev/null
+++ b/tests/lookups/mmacroamb.nim
@@ -0,0 +1,10 @@
+# issue #12732
+
+import std/macros
+const getPrivate3_tmp* = 0
+const foobar1* = 0 # comment this or make private and it'll compile fine
+macro foobar4*(): untyped =
+  newLit "abc"
+template currentPkgDir2*: string = foobar4()
+macro currentPkgDir2*(dir: string): untyped =
+  newLit "abc2"
diff --git a/tests/lookups/t23749.nim b/tests/lookups/t23749.nim
new file mode 100644
index 000000000..650f04ea4
--- /dev/null
+++ b/tests/lookups/t23749.nim
@@ -0,0 +1,37 @@
+discard """
+  action: compile
+"""
+
+{.pragma: callback, gcsafe, raises: [].}
+
+type
+  DataProc* = proc(val: openArray[byte]) {.callback.}
+  GetProc = proc (db: RootRef, key: openArray[byte], onData: DataProc): bool {.nimcall, callback.}
+  KvStoreRef* = ref object
+    obj: RootRef
+    getProc: GetProc
+
+template get(dbParam: KvStoreRef, key: openArray[byte], onData: untyped): bool =
+  let db = dbParam
+  db.getProc(db.obj, key, onData)
+
+func decode(input: openArray[byte], maxSize = 128): seq[byte] =
+  @[]
+
+proc getSnappySSZ(db: KvStoreRef, key: openArray[byte]): string =
+  var status = "not found"
+  proc decode(data: openArray[byte]) =
+    status =
+      if true: "found"
+      else: "corrupted"
+  discard db.get(key, decode)
+  status
+
+
+var ksr: KvStoreRef
+var k = [byte(1), 2, 3, 4, 5]
+
+proc foo(): string =
+  getSnappySSZ(ksr, toOpenArray(k, 1, 3))
+
+echo foo()
diff --git a/tests/lookups/tambtype.nim b/tests/lookups/tambtype.nim
new file mode 100644
index 000000000..a292db83a
--- /dev/null
+++ b/tests/lookups/tambtype.nim
@@ -0,0 +1,20 @@
+import ./mambtype2
+
+block: # issue #23893
+  discard default(K(0))       # works
+  discard default(mambtype2.B(0))     # works
+  discard default(mambtype2.K(0))     # doesn't work
+
+block: # issue #23898, in template
+  template r() =
+    discard default(B(0))     # compiles
+    discard default(mambtype2.B(0))   # compiles
+    discard default(K(0))     # does not compile
+  r()
+
+block: # in generics
+  proc foo[T]() =
+    discard default(B(0))     # compiles
+    discard default(mambtype2.B(0))   # compiles
+    discard default(K(0))     # does not compile
+  foo[int]()
diff --git a/tests/lookups/tdisambsym.nim b/tests/lookups/tdisambsym.nim
new file mode 100644
index 000000000..678528ad6
--- /dev/null
+++ b/tests/lookups/tdisambsym.nim
@@ -0,0 +1,8 @@
+# issue #15247
+
+import mdisambsym1, mdisambsym2, mdisambsym3
+
+proc twice(n: int): int =
+  n*2
+
+doAssert twice(count) == 20
diff --git a/tests/lookups/tenumlocalsym.nim b/tests/lookups/tenumlocalsym.nim
new file mode 100644
index 000000000..575227c07
--- /dev/null
+++ b/tests/lookups/tenumlocalsym.nim
@@ -0,0 +1,22 @@
+block:
+  type Enum = enum a, b
+
+  block:
+    let a = b
+    let x: Enum = a
+    doAssert x == b
+  
+block:
+  type
+    Enum = enum
+      a = 2
+      b = 10
+
+  iterator items2(): Enum =
+    for a in [a, b]:
+      yield a
+
+  var s = newSeq[Enum]()
+  for i in items2():
+    s.add i
+  doAssert s == @[a, b]
diff --git a/tests/lookups/tmacroamb.nim b/tests/lookups/tmacroamb.nim
new file mode 100644
index 000000000..854017e72
--- /dev/null
+++ b/tests/lookups/tmacroamb.nim
@@ -0,0 +1,5 @@
+# issue #12732
+
+import mmacroamb
+const s0 = currentPkgDir2 #[tt.Error
+           ^ ambiguous identifier: 'currentPkgDir2' -- use one of the following:]#
diff --git a/tests/lookups/tmoduleclash1.nim b/tests/lookups/tmoduleclash1.nim
new file mode 100644
index 000000000..7058f691e
--- /dev/null
+++ b/tests/lookups/tmoduleclash1.nim
@@ -0,0 +1,13 @@
+# issue #23596
+
+import std/heapqueue
+type Algo = enum heapqueue, quick
+when false:
+  let x = heapqueue
+let y: Algo = heapqueue
+proc bar*(algo=quick) =
+  var x: HeapQueue[int]
+  case algo
+  of heapqueue: echo 1 # `Algo.heapqueue` works on devel
+  of quick: echo 2
+  echo x.len
diff --git a/tests/lookups/tmoduleclash2.nim b/tests/lookups/tmoduleclash2.nim
new file mode 100644
index 000000000..958da2299
--- /dev/null
+++ b/tests/lookups/tmoduleclash2.nim
@@ -0,0 +1,6 @@
+import std/heapqueue
+proc heapqueue(x: int) = discard
+let x: proc (x: int) = heapqueue
+let y: proc = heapqueue
+when false:
+  let z = heapqueue
diff --git a/tests/macros/t23547.nim b/tests/macros/t23547.nim
new file mode 100644
index 000000000..9a2bff9ff
--- /dev/null
+++ b/tests/macros/t23547.nim
@@ -0,0 +1,23 @@
+# https://github.com/nim-lang/Nim/issues/23547
+
+type
+  A[T] = object
+    x: T
+
+proc mulCheckSparse[F](dummy: var A[F], xmulchecksparse: static A[F]) =
+  static:
+    echo "mulCheckSparse: ", typeof(dummy), ", ", typeof(xmulchecksparse) # when generic params not specified: A[system.int], A
+
+template sumImpl(xsumimpl: typed) =
+  static:
+    echo "sumImpl: ", typeof(xsumimpl) # A
+  var a = A[int](x: 55)
+  mulCheckSparse(a, xsumimpl) # fails here
+
+proc sum[T](xsum: static T) =
+  static:
+    echo "sum: ", typeof(xsum) # A[system.int]
+  sumImpl(xsum)
+
+const constA = A[int](x : 100)
+sum[A[int]](constA)
diff --git a/tests/macros/t23784.nim b/tests/macros/t23784.nim
new file mode 100644
index 000000000..31b4544c6
--- /dev/null
+++ b/tests/macros/t23784.nim
@@ -0,0 +1,157 @@
+discard """
+  joinable: false
+"""
+
+
+# debug ICE: genCheckedRecordField
+# apparently after https://github.com/nim-lang/Nim/pull/23477
+
+# bug #23784
+
+import std/bitops, std/macros
+
+# --------------------------------------------------------------
+
+type Algebra = enum
+  BN254_Snarks
+
+type SecretWord* = distinct uint64
+const WordBitWidth* = sizeof(SecretWord) * 8
+
+func wordsRequired*(bits: int): int {.inline.} =
+  const divShiftor = fastLog2(WordBitWidth)
+  result = (bits + WordBitWidth - 1) shr divShiftor
+
+type
+  BigInt*[bits: static int] = object
+    limbs*: array[bits.wordsRequired, SecretWord]  # <--- crash points to here
+
+# --------------------------------------------------------------
+
+const CurveBitWidth = [
+  BN254_Snarks: 254
+]
+
+const BN254_Snarks_Modulus = BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x2, SecretWord 0x3, SecretWord 0x4])
+const BN254_Snarks_Order = BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x1, SecretWord 0x2, SecretWord 0x2])
+
+func montyOne*(M: BigInt[254]): BigInt[254] =
+  ## Returns "1 (mod M)" in the Montgomery domain.
+  ## This is equivalent to R (mod M) in the natural domain
+  BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x1, SecretWord 0x1, SecretWord 0x1])
+
+
+{.experimental: "dynamicBindSym".}
+
+type
+  DerivedConstantMode* = enum
+    kModulus
+    kOrder
+
+macro genDerivedConstants*(mode: static DerivedConstantMode): untyped =
+  ## Generate constants derived from the main constants
+  ##
+  ## For example
+  ## - the Montgomery magic constant "R^2 mod N" in ROM
+  ##   For each curve under the private symbol "MyCurve_R2modP"
+  ## - the Montgomery magic constant -1/P mod 2^Wordbitwidth
+  ##   For each curve under the private symbol "MyCurve_NegInvModWord
+  ## - ...
+
+  # Now typedesc are NimNode and there is no way to translate
+  # NimNode -> typedesc easily so we can't
+  # "for curve in low(Curve) .. high(Curve):"
+  # As an ugly workaround, we count
+  # The item at position 0 is a pragma
+  result = newStmtList()
+
+  template used(name: string): NimNode =
+    nnkPragmaExpr.newTree(
+      ident(name),
+      nnkPragma.newTree(ident"used")
+    )
+
+  let ff = if mode == kModulus: "_Fp" else: "_Fr"
+
+  for curveSym in low(Algebra) .. high(Algebra):
+    let curve = $curveSym
+    let M = if mode == kModulus: bindSym(curve & "_Modulus")
+            else: bindSym(curve & "_Order")
+
+    # const MyCurve_montyOne = montyOne(MyCurve_Modulus)
+    result.add newConstStmt(
+      used(curve & ff & "_MontyOne"), newCall(
+        bindSym"montyOne",
+        M
+      )
+    )
+
+# --------------------------------------------------------------
+
+{.experimental: "dynamicBindSym".}
+
+genDerivedConstants(kModulus)
+genDerivedConstants(kOrder)
+
+proc bindConstant(ff: NimNode, property: string): NimNode =
+  # Need to workaround https://github.com/nim-lang/Nim/issues/14021
+  # which prevents checking if a type FF[Name] = Fp[Name] or Fr[Name]
+  # was instantiated with Fp or Fr.
+  # getTypeInst only returns FF and sameType doesn't work.
+  # so quote do + when checks.
+  let T = getTypeInst(ff)
+  T.expectKind(nnkBracketExpr)
+  doAssert T[0].eqIdent("typedesc")
+
+  let curve =
+    if T[1].kind == nnkBracketExpr: # typedesc[Fp[BLS12_381]] as used internally
+      # doAssert T[1][0].eqIdent"Fp" or T[1][0].eqIdent"Fr", "Found ident: '" & $T[1][0] & "' instead of 'Fp' or 'Fr'"
+      T[1][1].expectKind(nnkIntLit) # static enum are ints in the VM
+      $Algebra(T[1][1].intVal)
+    else: # typedesc[bls12381_fp] alias as used for C exports
+      let T1 = getTypeInst(T[1].getImpl()[2])
+      if T1.kind != nnkBracketExpr or
+         T1[1].kind != nnkIntLit:
+        echo T.repr()
+        echo T1.repr()
+        echo getTypeInst(T1).treerepr()
+        error "getTypeInst didn't return the full instantiation." &
+          " Dealing with types in macros is hard, complain at https://github.com/nim-lang/RFCs/issues/44"
+      $Algebra(T1[1].intVal)
+
+  let curve_fp = bindSym(curve & "_Fp_" & property)
+  let curve_fr = bindSym(curve & "_Fr_" & property)
+  result = quote do:
+    when `ff` is Fp:
+      `curve_fp`
+    elif `ff` is Fr:
+      `curve_fr`
+    else:
+      {.error: "Unreachable, received type: " & $`ff`.}
+
+# --------------------------------------------------------------
+
+template matchingBigInt*(Name: static Algebra): untyped =
+  ## BigInt type necessary to store the prime field Fp
+  # Workaround: https://github.com/nim-lang/Nim/issues/16774
+  # as we cannot do array accesses in type section.
+  # Due to generic sandwiches, it must be exported.
+  BigInt[CurveBitWidth[Name]]
+
+type
+  Fp*[Name: static Algebra] = object
+    mres*: matchingBigInt(Name)
+
+macro getMontyOne*(ff: type Fp): untyped =
+  ## Get one in Montgomery representation (i.e. R mod P)
+  result = bindConstant(ff, "MontyOne")
+
+func getOne*(T: type Fp): T {.noInit, inline.} =
+  result = cast[ptr T](unsafeAddr getMontyOne(T))[]
+
+# --------------------------------------------------------------
+proc foo(T: Fp) =
+  discard T
+
+let a = Fp[BN254_Snarks].getOne()
+foo(a) # oops this was a leftover that broke the bisect.
diff --git a/tests/macros/tastrepr.nim b/tests/macros/tastrepr.nim
index 668904cae..96a37c7a2 100644
--- a/tests/macros/tastrepr.nim
+++ b/tests/macros/tastrepr.nim
@@ -24,6 +24,9 @@ for i, (x, y) in pairs(data):
 var (a, b) = (1, 2)
 type
   A* = object
+
+var t04 = 1.0'f128
+t04 = 2.0'f128
 '''
 """
 
@@ -49,3 +52,7 @@ echoTypedAndUntypedRepr:
     discard
   var (a,b) = (1,2)
   type A* = object # issue #22933
+
+echoUntypedRepr:
+  var t04 = 1'f128
+  t04 = 2'f128
diff --git a/tests/macros/tgettypeinst7737.nim b/tests/macros/tgettypeinst7737.nim
new file mode 100644
index 000000000..e49f82562
--- /dev/null
+++ b/tests/macros/tgettypeinst7737.nim
@@ -0,0 +1,61 @@
+discard """
+  nimout: '''
+seq[int]
+CustomSeq[int]
+'''
+"""
+
+import macros, typetraits, sequtils
+
+block: # issue #7737 original
+  type
+    CustomSeq[T] = object
+      data: seq[T]
+
+  proc getSubType(T: NimNode): NimNode =
+    echo getTypeInst(T).repr
+    result = getTypeInst(T)[1]
+
+  macro typed_helper(x: varargs[typed]): untyped =
+    let foo = getSubType(x[0])
+    result = quote do: discard
+
+  macro untyped_heavylifting(x: varargs[untyped]): untyped =
+    var containers = nnkArgList.newTree()
+    for arg in x:
+      case arg.kind:
+      of nnkInfix:
+        if eqIdent(arg[0], "in"):
+          containers.add arg[2]
+      else:
+        discard
+    result = quote do:
+      typed_helper(`containers`)
+  var a, b, c: seq[int]
+  untyped_heavylifting z in c, x in a, y in b:
+    discard
+  ## The following gives me CustomSeq instead
+  ## of CustomSeq[int] in getTypeInst
+  var u, v, w: CustomSeq[int]
+  untyped_heavylifting z in u, x in v, y in w:
+    discard
+
+block: # issue #7737 comment
+  type
+    CustomSeq[T] = object
+      data: seq[T]
+  # when using just one argument, `foo` and `bar` should be exactly
+  # identical.
+  macro foo(arg: typed): string =
+    result = newLit(arg.getTypeInst.repr)
+  macro bar(args: varargs[typed]): untyped =
+    result = newTree(nnkBracket)
+    for arg in args:
+      result.add newLit(arg.getTypeInst.repr)
+  var
+    a: seq[int]
+    b: CustomSeq[int]
+  doAssert foo(a) == "seq[int]"
+  doAssert bar(a) == ["seq[int]"]
+  doAssert foo(b) == "CustomSeq[int]"
+  doAssert bar(b) == ["CustomSeq[int]"]
diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim
index 43819c81d..13b421303 100644
--- a/tests/macros/tmacrotypes.nim
+++ b/tests/macros/tmacrotypes.nim
@@ -1,9 +1,9 @@
 discard """
-  nimout: '''intProc; ntyProc; proc[int, int, float]; proc (a: int; b: float): int
+  nimout: '''intProc; ntyProc; proc[int, int, float]; proc (a: int; b: float): int {.nimcall.}
 void; ntyVoid; void; void
 int; ntyInt; int; int
-proc (); ntyProc; proc[void]; proc ()
-voidProc; ntyProc; proc[void]; proc ()
+proc () {.nimcall.}; ntyProc; proc[void]; proc () {.nimcall.}
+voidProc; ntyProc; proc[void]; proc () {.nimcall.}
 listing fields for ObjType
 a: string
 b: int
diff --git a/tests/macros/tprocgettype.nim b/tests/macros/tprocgettype.nim
new file mode 100644
index 000000000..0c1cc4270
--- /dev/null
+++ b/tests/macros/tprocgettype.nim
@@ -0,0 +1,28 @@
+discard """
+  nimout: '''
+var x: proc () {.cdecl.} = foo
+var x: iterator (): int {.closure.} = bar
+'''
+"""
+
+# issue #19010
+
+import macros
+
+macro createVar(x: typed): untyped =
+  result = nnkVarSection.newTree:
+    newIdentDefs(ident"x", getTypeInst(x), copy(x))
+  
+  echo repr result
+
+block:
+  proc foo() {.cdecl.} = discard
+
+  createVar(foo)
+  x()
+
+block:
+  iterator bar(): int {.closure.} = discard
+
+  createVar(bar)
+  for a in x(): discard
diff --git a/tests/metatype/tmetatype_issues.nim b/tests/metatype/tmetatype_issues.nim
index 21c5c02f1..d33d8dd31 100644
--- a/tests/metatype/tmetatype_issues.nim
+++ b/tests/metatype/tmetatype_issues.nim
@@ -157,3 +157,12 @@ block t3338:
   var t2 = Bar[int32]()
   t2.add()
   doAssert t2.x == 5
+
+block: # issue #24203
+  proc b(G: typedesc) =
+    type U = G
+  template s(h: untyped) = h
+  s(b(typeof (0, 0)))
+  b(seq[int])
+  b((int, int))
+  b(typeof (0, 0))
diff --git a/tests/metatype/ttypedescnotnimnode.nim b/tests/metatype/ttypedescnotnimnode.nim
new file mode 100644
index 000000000..52a04815b
--- /dev/null
+++ b/tests/metatype/ttypedescnotnimnode.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "type mismatch: got <NimNode> but expected 'typedesc'"
+  line: 14
+"""
+
+import macros
+
+# This is the same example as ttypeselectors but using a proc instead of a macro
+# Instead of type mismatch for macro, proc just failed with internal error: getTypeDescAux(tyNone)
+# https://github.com/nim-lang/Nim/issues/7231
+
+proc getBase2*(bits: static[int]): typedesc =
+  if bits == 128:
+    result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint64"))
+  else:
+    result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint32"))
+
+type
+  MpUint2*[bits: static[int]] = getbase2(bits)
+# technically shouldn't error until instantiation, so instantiate it
+var x: MpUint2[123]
diff --git a/tests/metatype/ttypeselectors.nim b/tests/metatype/ttypeselectors.nim
index 5385a1be9..d0843511d 100644
--- a/tests/metatype/ttypeselectors.nim
+++ b/tests/metatype/ttypeselectors.nim
@@ -98,16 +98,3 @@ var c: Bar[32]
 echo sizeof(a)
 echo sizeof(b)
 echo sizeof(c)
-
-# This is the same example but using a proc instead of a macro
-# Instead of type mismatch for macro, proc just failed with internal error: getTypeDescAux(tyNone)
-# https://github.com/nim-lang/Nim/issues/7231
-
-proc getBase2*(bits: static[int]): typedesc =
-  if bits == 128:
-    result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint64"))
-  else:
-    result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint32"))
-
-type
-  MpUint2*[bits: static[int]] = getbase2(bits)
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
index bfaa23057..0523390a7 100644
--- a/tests/metatype/ttypetraits.nim
+++ b/tests/metatype/ttypetraits.nim
@@ -144,6 +144,32 @@ block distinctBase:
         doAssert($distinctBase(typeof(b2)) == "string")
         doAssert($distinctBase(typeof(c2)) == "int")
 
+block: # rangeBase
+  {.push warningAsError[EnumConv]: on.}
+  proc foo[T: not range](x: T): string =
+    $T & "(" & $x & ")"
+  proc foo[T: range](x: T): string =
+    "ranged(" & $low(T) & ".." & $high(T) & " of " & $rangeBase(T) & ") " & foo(rangeBase(x))
+  doAssert foo(123) == "int(123)"
+  type IntRange = range[0..3]
+  let x: IntRange = 2
+  doAssert foo(x) == "ranged(0..3 of int) int(2)"
+  type E = enum a, b, c, d, e, f
+  type EnumRange = range[c..e]
+  let y: EnumRange = d
+  doAssert foo(y) == "ranged(c..e of E) E(d)"
+  let z: range['a'..'z'] = 'g'
+  doAssert foo(z) == "ranged(a..z of char) char(g)"
+  {.pop.}
+
+  # works only with #24037:
+  var toChange: range[0..3] = 1
+  proc bar[T: int and not range](y: var T) =
+    inc y
+  doAssert not compiles(bar(toChange))
+  bar(rangeBase(toChange))
+  doAssert toChange == 2
+
 block: # tupleLen
   doAssert not compiles(tupleLen(int))
 
@@ -365,3 +391,14 @@ block: # enum.len
     doAssert MyEnum.enumLen == 4
     doAssert OtherEnum.enumLen == 3
     doAssert MyFlag.enumLen == 4
+
+when true: # Odd bug where alias can seep inside of `distinctBase`
+  import std/unittest
+
+  type
+    AdtChild* = concept t
+      distinctBase(t)
+
+  proc `$`*[T: AdtChild](adtChild: T): string = ""
+
+  check 10 is int
diff --git a/tests/metatype/twrong_same_type.nim b/tests/metatype/twrong_same_type.nim
new file mode 100644
index 000000000..ea903b7a3
--- /dev/null
+++ b/tests/metatype/twrong_same_type.nim
@@ -0,0 +1,28 @@
+# bug #23418
+
+template mapIt*(x: untyped): untyped =
+  type OutType {.gensym.} = typeof(x) #typeof(x, typeOfProc)
+  newSeq[OutType](5)
+
+type F[E] = object
+
+proc start(v: int): F[(ValueError,)] = discard
+proc stop(v: int): F[tuple[]] = discard
+
+assert $typeof(mapIt(start(9))) == "seq[F[(ValueError,)]]"
+assert $typeof(mapIt(stop(9))) == "seq[F[tuple[]]]"
+
+# bug #23445
+
+type F2[T; I: static int] = distinct int
+
+proc start2(v: int): F2[void, 22] = discard
+proc stop2(v: int): F2[void, 33] = discard
+
+var a = mapIt(start2(5))
+
+assert $type(a) == "seq[F2[system.void, 22]]", $type(a)
+
+var b = mapIt(stop2(5))
+
+assert $type(b) == "seq[F2[system.void, 33]]", $type(b)
diff --git a/tests/misc/mjsondoc.nim b/tests/misc/mjsondoc.nim
index e4642f0b4..016c8522d 100644
--- a/tests/misc/mjsondoc.nim
+++ b/tests/misc/mjsondoc.nim
@@ -9,3 +9,6 @@ const
 type
   MyEnum* = enum
     foo, bar
+
+proc foo2*[T: int, M: string, U](x: T, y: U, z: M) =
+  echo 1
diff --git a/tests/misc/t20883.nim b/tests/misc/t20883.nim
index d98feaa14..92e7929f4 100644
--- a/tests/misc/t20883.nim
+++ b/tests/misc/t20883.nim
@@ -1,8 +1,9 @@
 discard """
   action: reject
-  errormsg: "type mismatch: got <float64> but expected 'typeof(U(0.000001))'"
-  line: 8
-  column: 22
+nimout: '''
+t20883.nim(13, 4) template/generic instantiation of `foo` from here
+t20883.nim(9, 11) Error: cannot instantiate: 'U'
+'''
 """
 
 proc foo*[U](x: U = U(1e-6)) =
diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim
index 6d67b1c52..73196e76c 100644
--- a/tests/misc/tcast.nim
+++ b/tests/misc/tcast.nim
@@ -1,6 +1,7 @@
 discard """
   output: '''
 Hello World
+Hello World
 Hello World'''
   joinable: false
 """
@@ -8,7 +9,7 @@ type MyProc = proc() {.cdecl.}
 type MyProc2 = proc() {.nimcall.}
 type MyProc3 = proc() #{.closure.} is implicit
 
-proc testProc()  = echo "Hello World"
+proc testProc() {.exportc:"foo".} = echo "Hello World"
 
 template reject(x) = doAssert(not compiles(x))
 
@@ -23,6 +24,10 @@ proc callPointer(p: pointer) =
   ffunc0()
   ffunc1()
 
+    # bug #5901
+  proc foo() {.importc.}
+  (cast[proc(a: int) {.cdecl.}](foo))(5)
+
 callPointer(cast[pointer](testProc))
 
 reject: discard cast[enum](0)
diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim
index e4a99344a..90fae868b 100644
--- a/tests/misc/tconv.nim
+++ b/tests/misc/tconv.nim
@@ -88,6 +88,13 @@ block: # https://github.com/nim-lang/RFCs/issues/294
   reject: Goo(k2)
   reject: k2.Goo
 
+  type KooRange = range[k2..k2]
+  accept: KooRange(k2)
+  accept: k2.KooRange
+  let k2ranged: KooRange = k2
+  accept: Koo(k2ranged)
+  accept: k2ranged.Koo
+
 reject:
   # bug #18550
   proc f(c: char): cstring =
diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim
index f0262f528..6e5487d1b 100644
--- a/tests/misc/trunner.nim
+++ b/tests/misc/trunner.nim
@@ -224,13 +224,15 @@ sub/mmain.idx""", context
     doAssert exitCode == 0, msg
 
     let data = parseJson(readFile(output))["entries"]
-    doAssert data.len == 4
+    doAssert data.len == 5
     let doSomething = data[0]
     doAssert doSomething["name"].getStr == "doSomething"
     doAssert doSomething["type"].getStr == "skProc"
     doAssert doSomething["line"].getInt == 1
     doAssert doSomething["col"].getInt == 0
     doAssert doSomething["code"].getStr == "proc doSomething(x, y: int): int {.raises: [], tags: [], forbids: [].}"
+    let foo2 = data[4]
+    doAssert $foo2["signature"] == """{"arguments":[{"name":"x","type":"T"},{"name":"y","type":"U"},{"name":"z","type":"M"}],"genericParams":[{"name":"T","types":"int"},{"name":"M","types":"string"},{"name":"U"}]}"""
 
   block: # nim jsondoc # bug #11953
     let file = testsDir / "misc/mjsondoc.nim"
@@ -241,7 +243,7 @@ sub/mmain.idx""", context
     doAssert exitCode == 0, msg
 
     let data = parseJson(readFile(destDir / "mjsondoc.json"))["entries"]
-    doAssert data.len == 4
+    doAssert data.len == 5
     let doSomething = data[0]
     doAssert doSomething["name"].getStr == "doSomething"
     doAssert doSomething["type"].getStr == "skProc"
diff --git a/tests/misc/trunner_special.nim b/tests/misc/trunner_special.nim
index e13810722..e08b419b0 100644
--- a/tests/misc/trunner_special.nim
+++ b/tests/misc/trunner_special.nim
@@ -14,6 +14,10 @@ xxx test all tests/untestable/* here, possibly with adjustments to make running
 import std/[strformat,os,unittest,compilesettings]
 import stdtest/specialpaths
 
+
+from stdtest/testutils import disableSSLTesting
+
+
 const
   nim = getCurrentCompilerExe()
   mode = querySetting(backend)
@@ -29,4 +33,5 @@ proc main =
   block: # SSL certificate check integration tests
     runCmd fmt"{nim} r {options} -d:ssl --threads:on --mm:refc {testsDir}/untestable/thttpclient_ssl_remotenetwork.nim"
 
-main()
+when not disableSSLTesting():
+  main()
diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim
index 0d96a5e04..ce5334664 100644
--- a/tests/misc/tsizeof.nim
+++ b/tests/misc/tsizeof.nim
@@ -732,3 +732,11 @@ type
 
 doAssert sizeof(PackedUnion) == 11
 doAssert alignof(PackedUnion) == 1
+
+# bug #22553
+type
+  ChunkObj = object
+    data: UncheckedArray[byte]
+
+doAssert sizeof(ChunkObj) == 1
+doAssert offsetOf(ChunkObj, data) == 1
diff --git a/tests/modules/mincludeprefix.nim b/tests/modules/mincludeprefix.nim
new file mode 100644
index 000000000..6d557a430
--- /dev/null
+++ b/tests/modules/mincludeprefix.nim
@@ -0,0 +1 @@
+const bar = 456
diff --git a/tests/modules/mincludetemplate.nim b/tests/modules/mincludetemplate.nim
new file mode 100644
index 000000000..febe9bfcf
--- /dev/null
+++ b/tests/modules/mincludetemplate.nim
@@ -0,0 +1 @@
+const foo = 123
diff --git a/tests/modules/tincludeprefix.nim b/tests/modules/tincludeprefix.nim
new file mode 100644
index 000000000..d45a6eff3
--- /dev/null
+++ b/tests/modules/tincludeprefix.nim
@@ -0,0 +1,3 @@
+include ./[mincludeprefix, mincludetemplate]
+doAssert foo == 123
+doAssert bar == 456
diff --git a/tests/modules/tincludetemplate.nim b/tests/modules/tincludetemplate.nim
new file mode 100644
index 000000000..77e409ee5
--- /dev/null
+++ b/tests/modules/tincludetemplate.nim
@@ -0,0 +1,5 @@
+# issue #12539
+
+template includePath(n: untyped) = include ../modules/n # But `include n` works
+includePath(mincludetemplate)
+doAssert foo == 123
diff --git a/tests/modules/treorder.nim b/tests/modules/treorder.nim
index 286b50e22..ff0b2e071 100644
--- a/tests/modules/treorder.nim
+++ b/tests/modules/treorder.nim
@@ -8,6 +8,8 @@ defined
 
 {.experimental: "codeReordering".}
 
+{.push callconv: stdcall.}
+
 proc bar(x: T)
 
 proc foo() =
@@ -41,3 +43,5 @@ using
   my, omy: int
 
 goo(3, 4)
+
+{.pop.}
diff --git a/tests/msgs/tused2.nim b/tests/msgs/tused2.nim
index f80c198d8..5ccda7737 100644
--- a/tests/msgs/tused2.nim
+++ b/tests/msgs/tused2.nim
@@ -7,12 +7,12 @@ mused2a.nim(12, 6) Hint: 'fn1' is declared but not used [XDeclaredButNotUsed]
 mused2a.nim(16, 5) Hint: 'fn4' is declared but not used [XDeclaredButNotUsed]
 mused2a.nim(20, 7) Hint: 'fn7' is declared but not used [XDeclaredButNotUsed]
 mused2a.nim(23, 6) Hint: 'T1' is declared but not used [XDeclaredButNotUsed]
-mused2a.nim(1, 11) Warning: imported and not used: 'strutils' [UnusedImport]
-mused2a.nim(3, 9) Warning: imported and not used: 'os' [UnusedImport]
+mused2a.nim(1, 12) Warning: imported and not used: 'strutils' [UnusedImport]
+mused2a.nim(3, 10) Warning: imported and not used: 'os' [UnusedImport]
 mused2a.nim(5, 23) Warning: imported and not used: 'typetraits2' [UnusedImport]
-mused2a.nim(6, 9) Warning: imported and not used: 'setutils' [UnusedImport]
+mused2a.nim(6, 10) Warning: imported and not used: 'setutils' [UnusedImport]
 tused2.nim(42, 8) Warning: imported and not used: 'mused2a' [UnusedImport]
-tused2.nim(45, 11) Warning: imported and not used: 'strutils' [UnusedImport]
+tused2.nim(45, 12) Warning: imported and not used: 'strutils' [UnusedImport]
 '''
 """
 
diff --git a/tests/niminaction/Chapter8/sdl/sdl_test.nim b/tests/niminaction/Chapter8/sdl/sdl_test.nim
index 1c4d258fb..db1700e0d 100644
--- a/tests/niminaction/Chapter8/sdl/sdl_test.nim
+++ b/tests/niminaction/Chapter8/sdl/sdl_test.nim
@@ -18,7 +18,7 @@ renderer.setDrawColor 29, 64, 153, 255
 renderer.clear
 renderer.setDrawColor 255, 255, 255, 255
 
-when defined(c):
+when false: # no long work with gcc 14!
   # just to ensure code from NimInAction still works, but
   # the `else` branch would work as well in C mode
   var points = [
diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim
index 152b355f4..0cd05e4f3 100644
--- a/tests/objects/tobject_default_value.nim
+++ b/tests/objects/tobject_default_value.nim
@@ -121,7 +121,7 @@ template main {.dirty.} =
       rVal: R = default(R) # Works fine
       objVal = default(Obj)
 
-    doAssert rVal == 0 # it should be 1
+    doAssert rVal == 1
     doAssert objVal.r == 1
 
   block: # bug #16744
@@ -134,7 +134,7 @@ template main {.dirty.} =
       rVal: R = default(R) # Works fine
       objVal = Obj()
 
-    doAssert rVal == 0 # it should be 1
+    doAssert rVal == 1 # it should be 1
     doAssert objVal.r == 1
 
   block: # bug #3608
@@ -744,6 +744,37 @@ template main {.dirty.} =
       var b = default ArrayObj2
       doAssert b.list[North] == 1
 
+  block:
+    type limited_float = range[1.2..20.0]
+    doAssert default(limited_float) == 1.2
+
+
+  block:
+    type
+      range1 = range[1..10]
+      range2 = range[-1..10]
+
+    proc foo =
+      doAssert default(range1) == 1
+      doAssert default(range2) == -1
+
+      let s = default(array[5, range1])
+      doAssert s == [range1 1, 1, 1, 1, 1]
+
+    foo()
+
+  block:
+    type
+      Object = object
+        id: range[1.2..29.3]
+
+    var s = default(Object)
+    doAssert s.id == 1.2
+
+  block: # bug #23943
+    type limited_int = range[1..20]
+    var d: limited_int;
+    doAssert d == 1
 
 static: main()
 main()
diff --git a/tests/objects/trequireinit.nim b/tests/objects/trequireinit.nim
new file mode 100644
index 000000000..202667b02
--- /dev/null
+++ b/tests/objects/trequireinit.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "The MPlayerObj type doesn't have a default value. The following fields must be initialized: foo."
+"""
+
+type
+  MPlayerObj* {.requiresInit.} = object
+    foo: range[5..10] = 5
+
+var a: MPlayerObj
+echo a.foo
\ No newline at end of file
diff --git a/tests/openarray/topenarray.nim b/tests/openarray/topenarray.nim
index c752becf2..25b983651 100644
--- a/tests/openarray/topenarray.nim
+++ b/tests/openarray/topenarray.nim
@@ -48,6 +48,41 @@ proc main =
       doAssert testing(mySeq) == mySeq
       doAssert testing(mySeq[2..^2]) == mySeq[2..^2]
 
+  block: # bug #23321
+    block:
+      proc foo(x: openArray[int]) =
+        doAssert x[0] == 0
+
+      var d = new array[1, int]
+      foo d[].toOpenArray(0, 0)
+
+    block:
+      proc foo(x: openArray[int]) =
+        doAssert x[0] == 0
+
+      proc task(x: var array[1, int]): var array[1, int] =
+        result = x
+      var d: array[1, int]
+      foo task(d).toOpenArray(0, 0)
+
+    block:
+      proc foo(x: openArray[int]) =
+        doAssert x[0] == 0
+
+      proc task(x: var array[1, int]): lent array[1, int] =
+        result = x
+      var d: array[1, int]
+      foo task(d).toOpenArray(0, 0)
+
+    block:
+      proc foo(x: openArray[int]) =
+        doAssert x[0] == 0
+
+      proc task(x: var array[1, int]): ptr array[1, int] =
+        result = addr x
+      var d: array[1, int]
+      foo task(d)[].toOpenArray(0, 0)
+
 
 main()
 static: main()
diff --git a/tests/openarray/tuncheckedarray.nim b/tests/openarray/tuncheckedarray.nim
new file mode 100644
index 000000000..c8ca9d2d4
--- /dev/null
+++ b/tests/openarray/tuncheckedarray.nim
@@ -0,0 +1,19 @@
+discard """
+  exitcode: 0
+  targets: "c cpp"
+"""
+
+proc main =
+  block: # issue 19171
+    var a = ['A']
+    proc mutB(x: var openArray[char]) =
+      x[0] = 'B'
+    mutB(toOpenArray(cast[ptr UncheckedArray[char]](addr a), 0, 0))
+    doAssert a[0] == 'B'
+    proc mutC(x: var openArray[char]; c: char) =
+      x[0] = c
+    let p = cast[ptr UncheckedArray[char]](addr a)
+    mutC(toOpenArray(p, 0, 0), 'C')
+    doAssert p[0] == 'C'
+
+main()
diff --git a/tests/osproc/tnoexe.nim b/tests/osproc/tnoexe.nim
new file mode 100644
index 000000000..19a3cca67
--- /dev/null
+++ b/tests/osproc/tnoexe.nim
@@ -0,0 +1,27 @@
+discard """
+  output: '''true
+true'''
+"""
+
+import std/osproc
+
+const command = "lsaaa -lah"
+
+try:
+  let process = startProcess(command, options = {poUsePath})
+  discard process.waitForExit()
+except OSError as e:
+  echo e.errorCode != 0
+
+# `poEvalCommand`, invokes the system shell to run the specified command
+try:
+  let process = startProcess(command, options = {poUsePath, poEvalCommand})
+  # linux
+  let exitCode = process.waitForExit()
+  echo exitCode != 0
+except OSError as e:
+  # Because the implementation of `poEvalCommand` on different platforms is inconsistent, 
+  # Linux will not throw an exception, but Windows will throw an exception
+
+  # windows
+  echo e.errorCode != 0
diff --git a/tests/osproc/twaitforexit.nim b/tests/osproc/twaitforexit.nim
new file mode 100644
index 000000000..535faca63
--- /dev/null
+++ b/tests/osproc/twaitforexit.nim
@@ -0,0 +1,38 @@
+import std/[osproc, os, times]
+
+block: # bug #5091
+    when defined(linux):
+        const filename = "false"
+        var p = startProcess(filename, options = {poStdErrToStdOut, poUsePath})
+        os.sleep(1000) # make sure process has exited already
+
+        let atStart = getTime()
+        const msWait = 2000
+
+        try:
+            discard waitForExit(p, msWait)
+        except OSError:
+            discard
+
+        # check that we don't have to wait msWait milliseconds
+        doAssert(getTime() <  atStart + milliseconds(msWait))
+
+block: # bug #23825
+
+    # the sleep command might not be available in all Windows installations
+
+    when defined(linux):
+
+        var thr: array[0..99, Thread[int]]
+
+        proc threadFunc(i: int) {.thread.} =
+            let sleepTime = float(i) / float(thr.len + 1)
+            doAssert sleepTime < 1.0
+            let p = startProcess("sleep", workingDir = "", args = @[$sleepTime], options = {poUsePath, poParentStreams})
+            # timeout = 1_000_000 seconds ~= 278 hours ~= 11.5 days
+            doAssert p.waitForExit(timeout=1_000_000_000) == 0
+
+        for i in low(thr)..high(thr):
+            createThread(thr[i], threadFunc, i)
+
+        joinThreads(thr) 
diff --git a/tests/overload/m19737.nim b/tests/overload/m19737.nim
new file mode 100644
index 000000000..7f7ac98e2
--- /dev/null
+++ b/tests/overload/m19737.nim
@@ -0,0 +1,10 @@
+type
+  UInt128* = object
+    lo, hi: uint64
+
+func `<`*(x, y: UInt128): bool =
+  (x.hi < y.hi) or ((x.hi == y.hi) and (x.lo < y.lo))
+
+when not defined(works):
+  func `>`*(x, y: UInt128): bool =
+    (x.hi > y.hi) or ((x.hi == y.hi) and (x.lo > y.lo))
diff --git a/tests/overload/mvaruintconv.nim b/tests/overload/mvaruintconv.nim
new file mode 100644
index 000000000..b889c90cf
--- /dev/null
+++ b/tests/overload/mvaruintconv.nim
@@ -0,0 +1,145 @@
+import
+  std/[macros, tables, hashes]
+
+export
+  macros
+
+type
+  FieldDescription* = object
+    name*: NimNode
+    isPublic*: bool
+    isDiscriminator*: bool
+    typ*: NimNode
+    pragmas*: NimNode
+    caseField*: NimNode
+    caseBranch*: NimNode
+
+{.push raises: [].}
+
+func isTuple*(t: NimNode): bool =
+  t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple")
+
+macro isTuple*(T: type): untyped =
+  newLit(isTuple(getType(T)[1]))
+
+proc collectFieldsFromRecList(result: var seq[FieldDescription],
+                              n: NimNode,
+                              parentCaseField: NimNode = nil,
+                              parentCaseBranch: NimNode = nil,
+                              isDiscriminator = false) =
+  case n.kind
+  of nnkRecList:
+    for entry in n:
+      collectFieldsFromRecList result, entry,
+                               parentCaseField, parentCaseBranch
+  of nnkRecWhen:
+    for branch in n:
+      case branch.kind:
+      of nnkElifBranch:
+        collectFieldsFromRecList result, branch[1],
+                                 parentCaseField, parentCaseBranch
+      of nnkElse:
+        collectFieldsFromRecList result, branch[0],
+                                 parentCaseField, parentCaseBranch
+      else:
+        doAssert false
+
+  of nnkRecCase:
+    collectFieldsFromRecList result, n[0],
+                             parentCaseField,
+                             parentCaseBranch,
+                             isDiscriminator = true
+
+    for i in 1 ..< n.len:
+      let branch = n[i]
+      case branch.kind
+      of nnkOfBranch:
+        collectFieldsFromRecList result, branch[^1], n[0], branch
+      of nnkElse:
+        collectFieldsFromRecList result, branch[0], n[0], branch
+      else:
+        doAssert false
+
+  of nnkIdentDefs:
+    let fieldType = n[^2]
+    for i in 0 ..< n.len - 2:
+      var field: FieldDescription
+      field.name = n[i]
+      field.typ = fieldType
+      field.caseField = parentCaseField
+      field.caseBranch = parentCaseBranch
+      field.isDiscriminator = isDiscriminator
+
+      if field.name.kind == nnkPragmaExpr:
+        field.pragmas = field.name[1]
+        field.name = field.name[0]
+
+      if field.name.kind == nnkPostfix:
+        field.isPublic = true
+        field.name = field.name[1]
+
+      result.add field
+
+  of nnkSym:
+    result.add FieldDescription(
+      name: n,
+      typ: getType(n),
+      caseField: parentCaseField,
+      caseBranch: parentCaseBranch,
+      isDiscriminator: isDiscriminator)
+
+  of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty:
+    discard
+
+  else:
+    doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr
+
+proc collectFieldsInHierarchy(result: var seq[FieldDescription],
+                              objectType: NimNode) =
+  var objectType = objectType
+
+  objectType.expectKind {nnkObjectTy, nnkRefTy}
+
+  if objectType.kind == nnkRefTy:
+    objectType = objectType[0]
+
+  objectType.expectKind nnkObjectTy
+
+  var baseType = objectType[1]
+  if baseType.kind != nnkEmpty:
+    baseType.expectKind nnkOfInherit
+    baseType = baseType[0]
+    baseType.expectKind nnkSym
+    baseType = getImpl(baseType)
+    baseType.expectKind nnkTypeDef
+    baseType = baseType[2]
+    baseType.expectKind {nnkObjectTy, nnkRefTy}
+    collectFieldsInHierarchy result, baseType
+
+  let recList = objectType[2]
+  collectFieldsFromRecList result, recList
+
+proc recordFields*(typeImpl: NimNode): seq[FieldDescription] =
+  if typeImpl.isTuple:
+    for i in 1 ..< typeImpl.len:
+      result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1)))
+    return
+
+  let objectType = case typeImpl.kind
+    of nnkObjectTy: typeImpl
+    of nnkTypeDef: typeImpl[2]
+    else:
+      macros.error("object type expected", typeImpl)
+      return
+
+  collectFieldsInHierarchy(result, objectType)
+
+macro field*(obj: typed, fieldName: static string): untyped =
+  newDotExpr(obj, ident fieldName)
+
+proc skipPragma*(n: NimNode): NimNode =
+  if n.kind == nnkPragmaExpr: n[0]
+  else: n
+
+
+{.pop.}
diff --git a/tests/overload/t19737.nim b/tests/overload/t19737.nim
new file mode 100644
index 000000000..b33ba9d8b
--- /dev/null
+++ b/tests/overload/t19737.nim
@@ -0,0 +1,15 @@
+# issue #19737
+
+import ./m19737
+
+var m: seq[uint64]
+
+proc foo(x: bool) = discard
+
+proc test[T: uint64|uint32](s: var seq[T]) =
+  var tmp = newSeq[T](1)
+  s = newSeq[T](1)
+
+  foo s[0] > tmp[0]
+
+test(m)
diff --git a/tests/overload/t23755.nim b/tests/overload/t23755.nim
new file mode 100644
index 000000000..de338a2ce
--- /dev/null
+++ b/tests/overload/t23755.nim
@@ -0,0 +1,62 @@
+type
+  BigInt[bits: static int] = object
+    limbs: array[8, uint64]
+
+block:
+  proc view[N](a: array[N, uint64]) =
+    discard
+
+  proc view[N](a: var array[N, uint64]) =
+    discard
+
+  var r: BigInt[64]
+  r.limbs.view()
+
+
+type Limbs[N: static int] = array[N, uint64]
+
+block:
+  proc view(a: Limbs) =
+    discard
+
+  proc view(a: var Limbs) =
+    discard
+
+  var r: BigInt[64]
+  r.limbs.view()
+
+
+block:
+  type IntArray[N: static[int]] = array[N, int]
+
+  proc p[T](a: IntArray[T]): bool= true
+  proc p(a: IntArray[5]): bool= false
+
+  var s: IntArray[5]
+  doAssert s.p == false
+
+block:
+  type IntArray[N: static[int]] = array[N, int]
+
+  proc `$`(a: IntArray): string =
+    return "test"
+
+  var s: IntArray[5] = [1,1,1,1,1]
+  doAssert `$`(s) == "test"
+
+block: 
+  proc p[n:static[int]](a: array[n, char]):bool=true
+  proc p[T, IDX](a: array[IDX, T]):bool=false
+
+  var g: array[32, char]
+  doAssert p(g)
+
+block:  # issue #23823
+  func p[N,T](a, b: array[N,T]) =
+    discard
+
+  func p[N: static int; T](x, y: array[N, T]) =
+    discard
+
+  var a: array[5, int]
+  p(a,a)
diff --git a/tests/overload/t8829.nim b/tests/overload/t8829.nim
index fe0dbf2bf..85d87f136 100644
--- a/tests/overload/t8829.nim
+++ b/tests/overload/t8829.nim
@@ -2,7 +2,7 @@ block:
   let txt = "Hello World"
 
   template `[]`[T](p: ptr T, span: Slice[int]): untyped =
-    toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b)
+    toOpenArray(cast[ptr UncheckedArray[T]](p), span.a, span.b)
 
   doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == 
                 "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]"
@@ -12,7 +12,7 @@ block:
   let txt = "Hello World"
 
   template `[]`[T](p: ptr T, span: Slice[int]): untyped =
-    toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b)
+    toOpenArray(cast[ptr UncheckedArray[T]](p), span.a, span.b)
 
   doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == 
                 "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]"
diff --git a/tests/overload/tgenericalias.nim b/tests/overload/tgenericalias.nim
new file mode 100644
index 000000000..50a44bd32
--- /dev/null
+++ b/tests/overload/tgenericalias.nim
@@ -0,0 +1,13 @@
+block: # issue #13799
+  type
+    X[A, B] = object
+      a: A
+      b: B
+
+    Y[A] = X[A, int]
+  template s(T: type X): X = T()
+  template t[A, B](T: type X[A, B]): X[A, B] = T()
+  proc works1(): Y[int] = s(X[int, int])
+  proc works2(): Y[int] = t(X[int, int])
+  proc works3(): Y[int] = t(Y[int])
+  proc broken(): Y[int] = s(Y[int])
diff --git a/tests/overload/tor_isnt_better.nim b/tests/overload/tor_isnt_better.nim
index be1ad67bf..bee125386 100644
--- a/tests/overload/tor_isnt_better.nim
+++ b/tests/overload/tor_isnt_better.nim
@@ -16,3 +16,26 @@ block: # bug #8568
   proc g(a: D|E): string = "foo D|E"
   proc g(a: D): string = "foo D"
   doAssert g(D[int]()) == "foo D"
+
+type Obj1[T] = object
+  v: T
+converter toObj1[T](t: T): Obj1[T] = return Obj1[T](v: t)
+block: # issue #10019
+  proc fun1[T](elements: seq[T]): string = "fun1 seq"
+  proc fun1(o: object|tuple): string = "fun1 object|tuple"
+  proc fun2[T](elements: openArray[T]): string = "fun2 openarray"
+  proc fun2(o: object): string = "fun2 object"
+  proc fun_bug[T](elements: openArray[T]): string = "fun_bug openarray"
+  proc fun_bug(o: object|tuple):string = "fun_bug object|tuple"
+  proc main() =
+    var x = @["hello", "world"]
+    block:
+      # no ambiguity error shown here even though this would compile if we remove either 1st or 2nd overload of fun1
+      doAssert fun1(x) == "fun1 seq"
+    block:
+      # ditto
+      doAssert fun2(x) == "fun2 openarray"
+    block:
+      # Error: ambiguous call; both t0065.fun_bug(elements: openarray[T])[declared in t0065.nim(17, 5)] and t0065.fun_bug(o: object or tuple)[declared in t0065.nim(20, 5)] match for: (array[0..1, string])
+      doAssert fun_bug(x) == "fun_bug openarray"
+  main()
diff --git a/tests/overload/toverload_issues.nim b/tests/overload/toverload_issues.nim
index 5db7b54fa..26bf89091 100644
--- a/tests/overload/toverload_issues.nim
+++ b/tests/overload/toverload_issues.nim
@@ -77,27 +77,30 @@ testPred(1)
 
 
 
-# bug #6526
-type
-  BaseObj = ref object of RootObj
-  DerivedObj = ref object of BaseObj
-  OtherDerivate = ref object of BaseObj
-
-proc `==`*[T1, T2: BaseObj](a: T1, b: T2): bool =
-  echo "baseobj =="
-  return true
-
-let a = DerivedObj()
-let b = DerivedObj()
-echo a == b
-
-proc `==`*[T1, T2: OtherDerivate](a: T1, b: T2): bool =
-  echo "even better! =="
-  return true
-
-let a2 = OtherDerivate()
-let b2 = OtherDerivate()
-echo a2 == b2
+block: # bug #6526
+  type
+    BaseObj = ref object of RootObj
+    DerivedObj = ref object of BaseObj
+    OtherDerivate = ref object of BaseObj
+
+  proc p[T](a: T, b: T): bool =
+    assert false
+
+  proc p[T1, T2: BaseObj](a: T1, b: T2): bool =
+    echo "baseobj =="
+    return true
+
+  let a = DerivedObj()
+  let b = DerivedObj()
+  echo p(a,b)
+
+  proc p[T1, T2: OtherDerivate](a: T1, b: T2): bool =
+    echo "even better! =="
+    return true
+
+  let a2 = OtherDerivate()
+  let b2 = OtherDerivate()
+  echo p(a2, b2)
 
 
 
diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim
index 0741fce60..d195a069d 100644
--- a/tests/overload/toverload_various.nim
+++ b/tests/overload/toverload_various.nim
@@ -506,3 +506,63 @@ block:
   doAssert(p2(F(float,1.0),F(float,2)) == 3.0)
   doAssert(p2(F(float,1.0),F(float,2.0)) == 3.0)
   #doAssert(p2(F(float,1),F(int,2.0)) == 3.0)
+
+block: # PR #23870
+  type
+    A {.inheritable.} = object
+    B = object of A
+    C = object of B
+
+  proc p[T: A](x: T): int = 0
+  proc p[T: B](x: T): int = 1
+
+  proc d(x: A): int = 0
+  proc d(x: B): int = 1
+  
+  proc g[T:A](x: typedesc[T]): int = 0
+  proc g[T: B](x: typedesc[T]): int = 1
+  
+  proc f[T](x: typedesc[T]): int = 0
+  proc f[T:B](x: typedesc[T]): int = 1
+
+  assert p(C()) == 1
+  assert d(C()) == 1
+  assert g(C) == 1
+  assert f(C) == 1
+
+block: # PR #23870
+  type
+    A = object of RootObj
+    PT = proc(ev: A) {.closure.}
+    sdt = seq[(PT, PT)]
+
+  proc encap() =
+    proc p(a: A) {.closure.} =
+      discard
+
+    var s: sdt
+    s.add (p, nil)
+
+  encap()
+
+block: # PR #23870
+  type
+    A = object of RootObj
+    B = object of A
+    C = object of B
+
+  proc p(a: B | RootObj): int =
+    0
+
+  proc p(a: A | A): int =
+    1
+
+  assert p(C()) == 0
+
+  proc d(a: RootObj | B): int =
+    0
+
+  proc d(a: A | A): int =
+    1
+
+  assert d(C()) == 0
diff --git a/tests/overload/tuntypedarg.nim b/tests/overload/tuntypedarg.nim
new file mode 100644
index 000000000..9aa4fad3b
--- /dev/null
+++ b/tests/overload/tuntypedarg.nim
@@ -0,0 +1,19 @@
+import macros
+
+block: # issue #7385
+  type CustomSeq[T] = object
+    data: seq[T]
+  macro `[]`[T](s: CustomSeq[T], args: varargs[untyped]): untyped =
+    ## The end goal is to replace the joker "_" by something else
+    result = newIntLitNode(10)
+  proc foo1(): CustomSeq[int] =
+    result.data.newSeq(10)
+    # works since no overload matches first argument with type `CustomSeq`
+    # except magic `[]`, which always matches without checking arguments
+    doAssert result[_] == 10
+  doAssert foo1() == CustomSeq[int](data: newSeq[int](10))
+  proc foo2[T](): CustomSeq[T] =
+    result.data.newSeq(10)
+    # works fine with generic return type
+    doAssert result[_] == 10
+  doAssert foo2[int]() == CustomSeq[int](data: newSeq[int](10))
diff --git a/tests/overload/tvaruintconv.nim b/tests/overload/tvaruintconv.nim
new file mode 100644
index 000000000..87ebd285d
--- /dev/null
+++ b/tests/overload/tvaruintconv.nim
@@ -0,0 +1,207 @@
+discard """
+  action: compile
+"""
+
+# https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102
+# failed with "for a 'var' type a variable needs to be passed; but 'uint64(result)' is immutable"
+
+import
+  std/[typetraits, macros]
+
+type
+  DefaultFlavor = object
+
+template serializationFormatImpl(Name: untyped) {.dirty.} =
+  type Name = object
+
+template serializationFormat(Name: untyped) =
+  serializationFormatImpl(Name)
+
+template setReader(Format, FormatReader: distinct type) =
+  when arity(FormatReader) > 1:
+    template Reader(T: type Format, F: distinct type = DefaultFlavor): type = FormatReader[F]
+  else:
+    template ReaderType(T: type Format): type = FormatReader
+    template Reader(T: type Format): type = FormatReader
+
+template useDefaultReaderIn(T: untyped, Flavor: type) =
+  mixin Reader
+
+  template readValue(r: var Reader(Flavor), value: var T) =
+    mixin readRecordValue
+    readRecordValue(r, value)
+
+import mvaruintconv
+
+type
+  FieldTag[RecordType: object; fieldName: static string] = distinct void
+
+func declval*(T: type): T {.compileTime.} =
+  default(ptr T)[]
+
+macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped =
+  var typeAst = getType(T)[1]
+  var typeImpl: NimNode
+  let isSymbol = not typeAst.isTuple
+
+  if not isSymbol:
+    typeImpl = typeAst
+  else:
+    typeImpl = getImpl(typeAst)
+  result = newStmtList()
+
+  var i = 0
+  for field in recordFields(typeImpl):
+    let
+      fieldIdent = field.name
+      realFieldName = newLit($fieldIdent.skipPragma)
+      fieldName = realFieldName
+      fieldIndex = newLit(i)
+
+    let fieldNameDefs =
+      if isSymbol:
+        quote:
+          const fieldName {.inject, used.} = `fieldName`
+          const realFieldName {.inject, used.} = `realFieldName`
+      else:
+        quote:
+          const fieldName {.inject, used.} = $`fieldIndex`
+          const realFieldName {.inject, used.} = $`fieldIndex`
+
+    let field =
+      if isSymbol:
+        quote do: declval(`T`).`fieldIdent`
+      else:
+        quote do: declval(`T`)[`fieldIndex`]
+
+    result.add quote do:
+      block:
+        `fieldNameDefs`
+
+        template FieldType: untyped {.inject, used.} = typeof(`field`)
+
+        `body`
+
+  # echo repr(result)
+
+template enumAllSerializedFields(T: type, body): untyped =
+  enumAllSerializedFieldsImpl(T, body)
+
+type
+  FieldReader[RecordType, Reader] = tuple[
+    fieldName: string,
+    reader: proc (rec: var RecordType, reader: var Reader)
+                 {.gcsafe, nimcall.}
+  ]
+
+proc totalSerializedFieldsImpl(T: type): int =
+  mixin enumAllSerializedFields
+  enumAllSerializedFields(T): inc result
+
+template totalSerializedFields(T: type): int =
+  (static(totalSerializedFieldsImpl(T)))
+
+template GetFieldType(FT: type FieldTag): type =
+  typeof field(declval(FT.RecordType), FT.fieldName)
+
+proc makeFieldReadersTable(RecordType, ReaderType: distinct type,
+                           numFields: static[int]):
+                           array[numFields, FieldReader[RecordType, ReaderType]] =
+  mixin enumAllSerializedFields, handleReadException
+  var idx = 0
+
+  enumAllSerializedFields(RecordType):
+    proc readField(obj: var RecordType, reader: var ReaderType)
+                  {.gcsafe, nimcall.} =
+
+      mixin readValue
+
+      type F = FieldTag[RecordType, realFieldName]
+      field(obj, realFieldName) = reader.readValue(GetFieldType(F))
+
+    result[idx] = (fieldName, readField)
+    inc idx
+
+proc fieldReadersTable(RecordType, ReaderType: distinct type): auto =
+  mixin readValue
+  type T = RecordType
+  const numFields = totalSerializedFields(T)
+  var tbl {.threadvar.}: ref array[numFields, FieldReader[RecordType, ReaderType]]
+  if tbl == nil:
+    tbl = new typeof(tbl)
+    tbl[] = makeFieldReadersTable(RecordType, ReaderType, numFields)
+  return addr(tbl[])
+
+proc readValue(reader: var auto, T: type): T =
+  mixin readValue
+  reader.readValue(result)
+
+template decode(Format: distinct type,
+                 input: string,
+                 RecordType: distinct type): auto =
+  mixin Reader
+  block:  # https://github.com/nim-lang/Nim/issues/22874
+    var reader: Reader(Format)
+    reader.readValue(RecordType)
+
+template readValue(Format: type,
+                    ValueType: type): untyped =
+  mixin Reader, init, readValue
+  var reader: Reader(Format)
+  readValue reader, ValueType
+
+template parseArrayImpl(numElem: untyped,
+                        actionValue: untyped) =
+  actionValue
+
+serializationFormat Json
+template createJsonFlavor(FlavorName: untyped,
+                           skipNullFields = false) {.dirty.} =
+  type FlavorName = object
+
+  template Reader(T: type FlavorName): type = Reader(Json, FlavorName)
+type
+  JsonReader[Flavor = DefaultFlavor] = object
+
+Json.setReader JsonReader
+
+template parseArray(r: var JsonReader; body: untyped) =
+  parseArrayImpl(idx): body
+
+template parseArray(r: var JsonReader; idx: untyped; body: untyped) =
+  parseArrayImpl(idx): body
+
+proc readRecordValue[T](r: var JsonReader, value: var T) =
+  type
+    ReaderType {.used.} = type r
+    T = type value
+
+  discard T.fieldReadersTable(ReaderType)
+
+proc readValue[T](r: var JsonReader, value: var T) =
+  mixin readValue
+
+  when value is seq:
+    r.parseArray:
+      readValue(r, value[0])
+
+  elif value is object:
+    readRecordValue(r, value)
+
+type
+  RemoteSignerInfo = object
+    id: uint32
+  RemoteKeystore = object
+
+proc readValue(reader: var JsonReader, value: var RemoteKeystore) =
+  discard reader.readValue(seq[RemoteSignerInfo])
+
+createJsonFlavor RestJson
+useDefaultReaderIn(RemoteSignerInfo, RestJson)
+proc readValue(reader: var JsonReader[RestJson], value: var uint64) =
+  discard reader.readValue(string)
+
+discard Json.decode("", RemoteKeystore)
+block:  # https://github.com/nim-lang/Nim/issues/22874
+  var reader: Reader(RestJson)
+  discard reader.readValue(RemoteSignerInfo)
diff --git a/tests/parallel/tsendtwice.nim b/tests/parallel/tsendtwice.nim
index 6bf5e5ebb..9f4a2e06e 100644
--- a/tests/parallel/tsendtwice.nim
+++ b/tests/parallel/tsendtwice.nim
@@ -1,18 +1,10 @@
 discard """
-  output: '''ob2 @[]
-ob @[]
-ob3 @[]
-3
-ob2 @[]
-ob @[]
-ob3 @[]
-'''
   matrix: "--mm:refc"
 """
 
 # bug #4776
 
-import tables
+import tables, algorithm
 
 type
   Base* = ref object of RootObj
@@ -35,20 +27,21 @@ globalTable.add("ob", d)
 globalTable.add("ob2", d)
 globalTable.add("ob3", d)
 
+proc `<`(x, y: seq[int]): bool = x.len < y.len
+proc kvs(t: TableRef[string, Base]): seq[(string, seq[int])] =
+  for k, v in t.pairs: result.add (k, v.someSeq)
+  result.sort
+
 proc testThread(channel: ptr TableChannel) {.thread.} =
   globalTable = channel[].recv()
-  for k, v in pairs globaltable:
-    echo k, " ", v.someSeq
   var myObj: Base
   deepCopy(myObj, globalTable["ob"])
   myObj.someSeq = newSeq[int](100)
   let table = channel[].recv() # same table
-  echo table.len
-  for k, v in mpairs table:
-    echo k, " ", v.someSeq
   assert(table.contains("ob")) # fails!
   assert(table.contains("ob2")) # fails!
   assert(table.contains("ob3")) # fails!
+  assert table.kvs == globalTable.kvs # Last to see above spot checks first
 
 var channel: TableChannel
 
diff --git a/tests/parser/tbinarynotindented.nim b/tests/parser/tbinarynotindented.nim
new file mode 100644
index 000000000..8d124aade
--- /dev/null
+++ b/tests/parser/tbinarynotindented.nim
@@ -0,0 +1,3 @@
+type Foo = ref int
+  not nil #[tt.Error
+  ^ invalid indentation]#
diff --git a/tests/parser/tbinarynotsameline.nim b/tests/parser/tbinarynotsameline.nim
new file mode 100644
index 000000000..ca417e023
--- /dev/null
+++ b/tests/parser/tbinarynotsameline.nim
@@ -0,0 +1,10 @@
+# issue #23565
+
+func foo: bool =
+  true
+
+const bar = block:
+  type T = int
+  not foo()
+
+doAssert not bar
diff --git a/tests/pragmas/mqualifiedmacro.nim b/tests/pragmas/mqualifiedmacro.nim
new file mode 100644
index 000000000..908973206
--- /dev/null
+++ b/tests/pragmas/mqualifiedmacro.nim
@@ -0,0 +1,10 @@
+template t*(x:untyped): untyped = 
+  echo "template t"
+
+import macros
+macro m*(name: static string, x: untyped): untyped =
+  let newName = ident(name)
+  result = quote do:
+    type `newName` = object
+  if result.kind == nnkStmtList:
+    result = result[^1]
diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim
index 9ffa9a33d..11a6df813 100644
--- a/tests/pragmas/tcustom_pragma.nim
+++ b/tests/pragmas/tcustom_pragma.nim
@@ -531,3 +531,10 @@ block:
 
   check(a)
   check(b)
+
+block: # https://forum.nim-lang.org/t/12522, backticks
+  template `mypragma`() {.pragma.}
+  # Error: invalid pragma: `mypragma`
+  type Test = object
+    field {.`mypragma`.}: int
+  doAssert Test().field.hasCustomPragma(mypragma)
diff --git a/tests/pragmas/tpush.nim b/tests/pragmas/tpush.nim
index 8ebbfe3d3..9c6b85c4e 100644
--- a/tests/pragmas/tpush.nim
+++ b/tests/pragmas/tpush.nim
@@ -99,3 +99,46 @@ block: # bug #23019
   k(w)
   {.pop.}
   {.pop.}
+
+{.push exportC.}
+
+block:
+  proc foo11() =
+    const factor = [1, 2, 3, 4]
+    doAssert factor[0] == 1
+  proc foo21() =
+    const factor = [1, 2, 3, 4]
+    doAssert factor[0] == 1
+
+  foo11()
+  foo21()
+
+template foo31() =
+  let factor = [1, 2, 3, 4]
+  doAssert factor[0] == 1
+template foo41() =
+  let factor = [1, 2, 3, 4]
+  doAssert factor[0] == 1
+
+foo31()
+foo41()
+
+{.pop.}
+
+import macros
+
+block:
+  {.push deprecated.}
+  template test() = discard
+  test()
+  {.pop.}
+  macro foo(): bool =
+    let ast = getImpl(bindSym"test")
+    var found = false
+    if ast[4].kind == nnkPragma:
+      for x in ast[4]:
+        if x.eqIdent"deprecated":
+          found = true
+          break
+    result = newLit(found)
+  doAssert foo()
diff --git a/tests/pragmas/tpushnotes.nim b/tests/pragmas/tpushnotes.nim
new file mode 100644
index 000000000..27ba0bec4
--- /dev/null
+++ b/tests/pragmas/tpushnotes.nim
@@ -0,0 +1,13 @@
+discard """
+  matrix: "--warningAsError:HoleEnumConv"
+"""
+
+type
+  e = enum
+    a = 0
+    b = 2
+
+var i: int
+{.push warning[HoleEnumConv]:off.}
+discard i.e
+{.pop.}
diff --git a/tests/pragmas/tqualifiedmacro.nim b/tests/pragmas/tqualifiedmacro.nim
new file mode 100644
index 000000000..bc95ec1ea
--- /dev/null
+++ b/tests/pragmas/tqualifiedmacro.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''
+template t
+'''
+"""
+
+# issue #12696
+
+import mqualifiedmacro
+proc p() {. mqualifiedmacro.t .} = # errors with identifier expected but a.t found
+  echo "proc p"
+
+type Foo {. mqualifiedmacro.m("Bar") .} = object
+doAssert Bar is object
diff --git a/tests/proc/t23874.nim b/tests/proc/t23874.nim
new file mode 100644
index 000000000..940bc4ac8
--- /dev/null
+++ b/tests/proc/t23874.nim
@@ -0,0 +1,26 @@
+block:
+  type Head[T] = object
+    wasc: bool
+
+  proc `=destroy`[T](x: var Head[T]) =
+    discard
+
+  proc `=copy`[T](x: var Head[T], y: Head[T]) =
+    x.wasc = true
+
+  proc `=dup`[T](x: Head[T]): Head[T] =
+    result.wasc = true
+
+  proc update(h: var Head) =
+    discard
+
+  proc digest(h: sink Head) =
+    assert h.wasc
+
+  var h = Head[int](wasc: false)
+  h.digest() # sink h
+  h.update() # use after sink
+
+block:
+  proc two(a: sink auto) =discard
+  assert typeof(two[int]) is proc(a: sink int) {.nimcall.}
diff --git a/tests/proc/texplicitgenericcount.nim b/tests/proc/texplicitgenericcount.nim
new file mode 100644
index 000000000..8654a1d13
--- /dev/null
+++ b/tests/proc/texplicitgenericcount.nim
@@ -0,0 +1,24 @@
+discard """
+  cmd: "nim check -d:testsConciseTypeMismatch $file"
+"""
+
+proc foo[T, U](x: T, y: U): (T, U) = (x, y)
+
+let x = foo[int](1, 2) #[tt.Error
+                ^ type mismatch
+Expression: foo[int](1, 2)
+  [1] 1: int literal(1)
+  [2] 2: int literal(2)
+
+Expected one of (first mismatch at [position]):
+[2] proc foo[T, U](x: T; y: U): (T, U)
+  missing generic parameter: U]#
+let y = foo[int, float, string](1, 2) #[tt.Error
+                               ^ type mismatch
+Expression: foo[int, float, string](1, 2)
+  [1] 1: int literal(1)
+  [2] 2: int literal(2)
+
+Expected one of (first mismatch at [position]):
+[3] proc foo[T, U](x: T; y: U): (T, U)
+  extra generic param given]#
diff --git a/tests/proc/texplicitgenericcountverbose.nim b/tests/proc/texplicitgenericcountverbose.nim
new file mode 100644
index 000000000..76228eeaf
--- /dev/null
+++ b/tests/proc/texplicitgenericcountverbose.nim
@@ -0,0 +1,22 @@
+discard """
+  cmd: "nim check $file"
+"""
+
+proc foo[T, U](x: T, y: U): (T, U) = (x, y)
+
+let x = foo[int](1, 2) #[tt.Error
+                ^ type mismatch: got <int literal(1), int literal(2)>
+but expected one of:
+proc foo[T, U](x: T; y: U): (T, U)
+  first type mismatch at position: 2 in generic parameters
+  missing generic parameter: U
+
+expression: foo[int](1, 2)]#
+let y = foo[int, float, string](1, 2) #[tt.Error
+                               ^ type mismatch: got <int literal(1), int literal(2)>
+but expected one of:
+proc foo[T, U](x: T; y: U): (T, U)
+  first type mismatch at position: 3 in generic parameters
+  extra generic param given
+
+expression: foo[int, float, string](1, 2)]#
diff --git a/tests/proc/texplicitgenerics.nim b/tests/proc/texplicitgenerics.nim
new file mode 100644
index 000000000..833d77b3b
--- /dev/null
+++ b/tests/proc/texplicitgenerics.nim
@@ -0,0 +1,55 @@
+block: # issue #16376
+  type
+    Matrix[T] = object
+      data: T
+  proc randMatrix[T](m, n: int, max: T): Matrix[T] = discard
+  proc randMatrix[T](m, n: int, x: Slice[T]): Matrix[T] = discard
+  template randMatrix[T](m, n: int): Matrix[T] = randMatrix[T](m, n, T(1.0))
+  let B = randMatrix[float32](20, 10)
+
+block: # different generic param counts 
+  type
+    Matrix[T] = object
+      data: T
+  proc randMatrix[T](m: T, n: T): Matrix[T] = Matrix[T](data: T(1.0))
+  proc randMatrix[T; U: not T](m: T, n: U): (Matrix[T], U) = (Matrix[T](data: T(1.0)), default(U))
+  let b = randMatrix[float32](20, 10)
+  doAssert b == Matrix[float32](data: 1.0)
+
+block: # above for templates 
+  type
+    Matrix[T] = object
+      data: T
+  template randMatrix[T](m: T, n: T): Matrix[T] = Matrix[T](data: T(1.0))
+  template randMatrix[T; U: not T](m: T, n: U): (Matrix[T], U) = (Matrix[T](data: T(1.0)), default(U))
+  let b = randMatrix[float32](20, 10)
+  doAssert b == Matrix[float32](data: 1.0)
+
+block: # sigmatch can't handle this without pre-instantiating the type:
+  # minimized from numericalnim
+  type Foo[T] = proc (x: T)
+  proc foo[T](x: T) = discard
+  proc bar[T](f: Foo[T]) = discard
+  bar[int](foo)
+
+block: # ditto but may be wrong minimization
+  # minimized from measuremancer
+  type Foo[T] = object
+  proc foo[T](): Foo[T] = Foo[T]()
+  # this is the actual issue but there are other instantiation problems
+  proc bar[T](x = foo[T]()) = discard
+  bar[int](Foo[int]())
+  bar[int]()
+  # alternative version, also causes instantiation issue
+  proc baz[T](x: typeof(foo[T]())) = discard
+  baz[int](Foo[int]())
+
+block: # issue #21346
+  type K[T] = object
+  template s[T](x: int) = doAssert T is K[K[int]]
+  proc b1(n: bool | bool) = s[K[K[int]]](3)
+  proc b2(n: bool)        = s[K[K[int]]](3)
+  template b3(n: bool)    = s[K[K[int]]](3)
+  b1(false)     # Error: cannot instantiate K; got: <T> but expected: <T>
+  b2(false)     # Builds, on its own
+  b3(false)
diff --git a/tests/proc/tgenericdefaultparam.nim b/tests/proc/tgenericdefaultparam.nim
new file mode 100644
index 000000000..7bce591ce
--- /dev/null
+++ b/tests/proc/tgenericdefaultparam.nim
@@ -0,0 +1,98 @@
+block: # issue #16700
+  type MyObject[T] = object
+    x: T
+  proc initMyObject[T](value = T.default): MyObject[T] =
+    MyObject[T](x: value)
+  var obj = initMyObject[int]()
+
+block: # issue #20916
+  type
+    SomeX = object
+      v: int
+  var val = 0
+  proc f(_: type int, x: SomeX, v = x.v) =
+    doAssert v == 42
+    val = v
+  proc a(): proc() =
+    let v = SomeX(v: 42)
+    var tmp = proc() =
+      int.f(v)
+    tmp
+  a()()
+  doAssert val == 42
+
+import std/typetraits
+
+block: # issue #24099, original example
+  type
+    ColorRGBU = distinct array[3, uint8] ## RGB range 0..255
+    ColorRGBAU = distinct array[4, uint8] ## RGB range 0..255
+    ColorRGBUAny = ColorRGBU | ColorRGBAU
+  template componentType(t: typedesc[ColorRGBUAny]): typedesc =
+    ## Returns component type of a given color type.
+    arrayType distinctBase t
+  func `~=`[T: ColorRGBUAny](a, b: T, e = componentType(T)(1.0e-11)): bool =
+    ## Compares colors with given accuracy.
+    abs(a[0] - b[0]) < e and abs(a[1] - b[1]) < e and abs(a[2] - b[2]) < e
+
+block: # issue #24099, modified to actually work
+  type
+    ColorRGBU = distinct array[3, uint8] ## RGB range 0..255
+    ColorRGBAU = distinct array[4, uint8] ## RGB range 0..255
+    ColorRGBUAny = ColorRGBU | ColorRGBAU
+  template arrayType[I, T](t: typedesc[array[I, T]]): typedesc =
+    T
+  template `[]`(a: ColorRGBUAny, i: untyped): untyped = distinctBase(a)[i]
+  proc abs(a: uint8): uint8 = a
+  template componentType(t: typedesc[ColorRGBUAny]): typedesc =
+    ## Returns component type of a given color type.
+    arrayType distinctBase t
+  func `~=`[T: ColorRGBUAny](a, b: T, e = componentType(T)(1.0e-11)): bool =
+    ## Compares colors with given accuracy.
+    abs(a[0] - b[0]) <= e and abs(a[1] - b[1]) <= e and abs(a[2] - b[2]) <= e
+  doAssert ColorRGBU([1.uint8, 1, 1]) ~= ColorRGBU([1.uint8, 1, 1])
+
+block: # issue #24099, modified to work but using float32
+  type
+    ColorRGBU = distinct array[3, float32] ## RGB range 0..255
+    ColorRGBAU = distinct array[4, float32] ## RGB range 0..255
+    ColorRGBUAny = ColorRGBU | ColorRGBAU
+  template arrayType[I, T](t: typedesc[array[I, T]]): typedesc =
+    T
+  template `[]`(a: ColorRGBUAny, i: untyped): untyped = distinctBase(a)[i]
+  template componentType(t: typedesc[ColorRGBUAny]): typedesc =
+    ## Returns component type of a given color type.
+    arrayType distinctBase t
+  func `~=`[T: ColorRGBUAny](a, b: T, e = componentType(T)(1.0e-11)): bool =
+    ## Compares colors with given accuracy.
+    abs(a[0] - b[0]) < e and abs(a[1] - b[1]) < e and abs(a[2] - b[2]) < e
+  doAssert ColorRGBU([1.float32, 1, 1]) ~= ColorRGBU([1.float32, 1, 1])
+
+block: # issue #13270
+  type
+    A = object
+    B = object
+  proc f(a: A) = discard
+  proc g[T](value: T, cb: (proc(a: T)) = f) =
+    cb value
+  g A()
+  # This should fail because there is no f(a: B) overload available
+  doAssert not compiles(g B())
+
+block: # issue #24121
+  type
+    Foo = distinct int
+    Bar = distinct int
+    FooBar = Foo | Bar
+
+  proc foo[T: distinct](x: T): string = "a"
+  proc foo(x: Foo): string = "b"
+  proc foo(x: Bar): string = "c"
+
+  proc bar(x: FooBar, y = foo(x)): string = y
+  doAssert bar(Foo(123)) == "b"
+  doAssert bar(Bar(123)) == "c"
+
+  proc baz[T: FooBar](x: T, y = foo(x)): string = y
+  doAssert baz(Foo(123)) == "b"
+  doAssert baz(Bar(123)) == "c"
diff --git a/tests/proc/tstaticsignature.nim b/tests/proc/tstaticsignature.nim
new file mode 100644
index 000000000..25aa09c5d
--- /dev/null
+++ b/tests/proc/tstaticsignature.nim
@@ -0,0 +1,268 @@
+block: # issue #4228
+  template seqType(t: typedesc): typedesc =
+    when t is int:
+      seq[int]
+    else:
+      seq[string]
+
+  proc mkSeq[T: int|string](v: T): seqType(T) =
+    result = newSeq[T](1)
+    result[0] = v
+
+  doAssert mkSeq("a") == @["a"]
+  doAssert mkSeq(1) == @[1]
+
+block: # expanded version of t8545
+  template bar(a: static[bool]): untyped =
+    when a:
+      int
+    else:
+      float
+
+  proc main() =
+    proc foo1(a: static[bool]): auto = 1
+    doAssert foo1(true) == 1
+
+    proc foo2(a: static[bool]): bar(a) = 1
+    doAssert foo2(true) == 1
+    doAssert foo2(true) is int
+    doAssert foo2(false) == 1.0
+    doAssert foo2(false) is float
+
+    proc foo3(a: static[bool]): bar(cast[bool](a)) = 1
+    doAssert foo3(true) == 1
+    doAssert foo3(true) is int
+    doAssert foo3(false) == 1.0
+    doAssert foo3(false) is float
+
+    proc foo4(a: static[bool]): bar(static(a)) = 1
+    doAssert foo4(true) == 1
+    doAssert foo4(true) is int
+    doAssert foo4(false) == 1.0
+    doAssert foo4(false) is float
+
+  static: main()
+  main()
+
+block: # issue #8406
+  macro f(x: static[int]): untyped = discard
+  proc g[X: static[int]](v: f(X)) = discard
+
+import macros
+
+block: # issue #8551
+  macro distinctBase2(T: typedesc): untyped =
+    let typeNode = getTypeImpl(T)
+    expectKind(typeNode, nnkBracketExpr)
+    if typeNode[0].typeKind != ntyTypeDesc:
+      error "expected typeDesc, got " & $typeNode[0]
+    var typeSym = typeNode[1]
+
+    typeSym = getTypeImpl(typeSym)
+
+    if typeSym.typeKind != ntyDistinct:
+      error "type is not distinct: " & $typeSym.typeKind
+
+    typeSym = typeSym[0]
+    typeSym
+
+  func distinctBase[T](a: T): distinctBase2(T) = distinctBase2(T)(a)
+
+  type T = distinct int
+  doAssert distinctBase(T(0)) is int
+
+block:
+  type Foo[T] = object
+    x: T
+
+  proc foo(x: Foo): Foo[x.T] =
+    doAssert typeof(result) is typeof(x)
+
+  var a: Foo[int]
+  let b: Foo[int] = foo(a)
+  doAssert b.x is int
+
+block:
+  type Foo[T: static int] = object
+    x: array[T, int]
+  
+  proc double(x: int): int = x * 2
+
+  proc foo[T: static int](x: Foo[T]): Foo[T.double] =
+    doAssert typeof(result).T == double(typeof(x).T)
+
+  var a: Foo[3]
+  let b: Foo[6] = foo(a)
+  doAssert $typeof(foo(a)) == "Foo[6]"
+
+block:
+  type Foo[T: static int] = object
+    x: array[T, int]
+
+  proc foo(x: Foo): Foo[x.T] =
+    doAssert typeof(result).T == typeof(x).T
+    doAssert typeof(result) is typeof(x)
+
+  var a: Foo[3]
+  let b: Foo[3] = foo(a)
+  doAssert $typeof(foo(a)) == "Foo[3]"
+
+block: # issue #7006
+  type
+    Node[T] = object
+      val: T
+      next: ref Node[T]
+    HHSet[T, Key] = object
+      data: seq[Node[T]]
+  proc rawGet(hhs:HHSet; key: hhs.Key): ptr Node[hhs.T] =
+    return nil # body doesn't matter
+  var hhs: HHSet[string, cstring]
+  discard hhs.rawGet("hello".cstring)
+
+block: # issue #7008
+  type Node[T] = object
+    val: T
+  # Compiles fine
+  proc concreteProc(s: Node[cstring]; key: s.T) = discard
+  # Also fine
+  proc implicitGenericProc1(s: Node; key: s.T) = discard
+  # still fine
+  proc explicitGenericProc1[T](s: Node[T]; key: T) = discard
+  # Internal Compiler Error!
+  proc explicitGenericProc2[T](s: Node[T]; key: s.T) = discard
+  let n = Node[int](val: 5)
+  implicitGenericProc1(n, 5) # works
+  explicitGenericProc1(n, 5) # works
+  explicitGenericProc2(n, 5) # doesn't
+
+block: # issue #20027
+  block:
+    type Test[T] = object
+    proc run(self: Test): self.T = discard
+    discard run(Test[int]())
+  block:
+    type Test[T] = object
+    proc run[T](self: Test[T]): self.T = discard
+    discard run(Test[int]())
+  block:
+    type Test[T] = object
+    proc run(self: Test[auto]): self.T = discard
+    discard run(Test[int]())
+
+block: # issue #11112
+  proc foo[A, B]: type(A.default + B.default) =
+    discard
+  doAssert foo[int, int]() is int
+
+block: # tyStatic and tyFromExpr instantiation mid-match
+  proc bar(x: int): int = x * 3
+  proc bar2(x: static int): int = x * 4
+  type Foo[T: static int] = distinct array[T, int]
+  proc foo[T: static int](x: Foo[T], y: Foo[bar(T)]) = discard
+  proc foo2[T: static int](x: Foo[T], y: Foo[bar2(T)]) = discard
+  foo(Foo[1]([1]), Foo[3]([1, 2, 3]))
+  foo2(Foo[1]([1]), Foo[4]([1, 2, 3, 4]))
+
+block: # issue #4990
+  type Foo[I: static[int], A: static[array[I, int]]] = object
+    curIndex: int
+
+  proc next[I: static[int], A: static[array[I, int]]](f: Foo[I, A]): string =
+    discard
+  const arr = [1, 2, 3]
+  var f: Foo[arr.len, arr]
+  discard next(f)
+
+block: # issue #4990 comment
+  type
+    Foo[A: static[int], B: static[int], TokenType: enum, EofToken: static[TokenType]] = object
+      curIndex: int
+    MyEnum = enum
+      meA, meB
+    Bar = Foo[2, 3, MyEnum, meA]
+  proc next[A: static[int], B: static[int], TokenType: enum,
+            EofToken: static[TokenType]](f: Foo[A, B, TokenType, EofToken],
+      a: static[(array[A, int], array[B, int])]): TokenType =
+    TokenType(a[0][f.curIndex])
+  const
+    a = [1, 2]
+    b = [3, 4, 5]
+  template next(bar: Bar): MyEnum =
+    next(Foo[2, 3, MyEnum, meA](bar), (a, b))
+  let bar = Bar(curIndex: 0)
+  doAssert bar.next() == meB
+
+block: # issue #14053
+  template returnType(value: static[int]): typedesc =
+    when value == 1:
+      int
+    else:
+      float
+  proc fun(value: static[int]): returnType(value) = discard
+  doAssert fun(1) is int
+  template returnType2(value: static[int]): typedesc =
+    int
+  proc fun2(value: static[int]): returnType2(value) = discard
+  doAssert fun2(1) is int
+
+block: # issue #7547
+  macro foo(N: static[int]): untyped =
+    result = getType(int)
+  type
+    Foo[N: static[int]] = foo(N)
+    ContainsFoo[N: static[int]] = object
+      Ffoo: Foo[N]
+  proc initFoo(N: static[int]): Foo[N] = discard
+  proc initContainsFoo(size: static[int]): ContainsFoo[size] = discard
+  var a: Foo[10] # Works
+  doAssert a is int
+  let b = initFoo(10) # Works
+  doAssert b is int
+  let c = ContainsFoo[5]() # Works
+  doAssert c.Ffoo is int
+  let z = initContainsFoo(5) # Error: undeclared identifier: 'N'
+  doAssert z.Ffoo is int
+
+block: # issue #22607, needs nkWhenStmt to be handled like nkRecWhen
+  proc test[x: static bool](
+    t: (
+      when x:
+        int
+      else:
+        float
+      )
+  ) = discard
+  test[true](1.int)
+  test[false](1.0)
+  doAssert not compiles(test[])
+
+block: # `when` in static signature
+  template ctAnd(a, b): bool =
+    when a:
+      when b: true
+      else: false
+    else: false
+  template test(): untyped =
+    when ctAnd(declared(SharedTable), typeof(result) is SharedTable):
+      result = SharedTable()
+    else:
+      result = 123
+  proc foo[T](): T = test()
+  proc bar[T](x = foo[T]()): T = x
+  doAssert bar[int]() == 123
+
+block: # issue #22276
+  type Foo = enum A, B
+  macro test(y: static[Foo]): untyped =
+    if y == A:
+      result = parseExpr("proc (x: int)")
+    else:
+      result = parseExpr("proc (x: float)")
+  proc foo(y: static[Foo], x: test(y)) = # We want to make the type of `x` depend on what `y` is
+    x(9)
+  foo(A, proc (x: int) = doAssert x == 9)
+  var a: int
+  foo(A, proc (x: int) =
+    a = x * 2)
+  doAssert a == 18
+  foo(B, proc (x: float) = doAssert x == 9)
diff --git a/tests/proc/twrongdefaultvalue.nim b/tests/proc/twrongdefaultvalue.nim
new file mode 100644
index 000000000..2c36c2247
--- /dev/null
+++ b/tests/proc/twrongdefaultvalue.nim
@@ -0,0 +1,25 @@
+discard """
+  cmd: "nim check $file"
+  action: reject
+  nimout: '''
+twrongdefaultvalue.nim(20, 12) template/generic instantiation of `doit` from here
+twrongdefaultvalue.nim(17, 37) Error: type mismatch: got <proc (p: int): Item[initItem.T]> but expected 'Item[system.string]'
+twrongdefaultvalue.nim(25, 3) template/generic instantiation of `foo` from here
+twrongdefaultvalue.nim(23, 33) Error: type mismatch: got <string> but expected 'int'
+'''
+"""
+
+block: # issue #21258
+  type Item[T] = object
+    pos: int
+  proc initItem[T](p:int=10000) : Item[T] = 
+    result = Item[T](p)
+  proc doit[T](x:Item[T], s:Item[T]=initItem) : string = 
+    return $x.pos
+  let x = Item[string](pos:100)
+  echo doit(x)
+
+block: # issue #21258, reduced case
+  proc foo[T](x: seq[T], y: T = "foo") =
+    discard
+  foo @[1, 2, 3]
diff --git a/tests/range/tcompiletime_range_checks.nim b/tests/range/tcompiletime_range_checks.nim
index 29e2c48a8..2d3f292ec 100644
--- a/tests/range/tcompiletime_range_checks.nim
+++ b/tests/range/tcompiletime_range_checks.nim
@@ -1,8 +1,8 @@
 discard """
   cmd: "nim check --hint:Processing:off --hint:Conf:off $file"
   errormsg: "18446744073709551615 can't be converted to int8"
-  nimout: '''tcompiletime_range_checks.nim(36, 21) Error: 2147483648 can't be converted to int32
-tcompiletime_range_checks.nim(37, 23) Error: -1 can't be converted to uint64
+  nimout: '''
+tcompiletime_range_checks.nim(36, 21) Error: 2147483648 can't be converted to int32
 tcompiletime_range_checks.nim(38, 34) Error: 255 can't be converted to FullNegativeRange
 tcompiletime_range_checks.nim(39, 34) Error: 18446744073709551615 can't be converted to HalfNegativeRange
 tcompiletime_range_checks.nim(40, 34) Error: 300 can't be converted to FullPositiveRange
diff --git a/tests/range/texplicitvarconv.nim b/tests/range/texplicitvarconv.nim
new file mode 100644
index 000000000..8da8a8878
--- /dev/null
+++ b/tests/range/texplicitvarconv.nim
@@ -0,0 +1,13 @@
+# related to issue #24032
+
+proc `++`(n: var int) =
+    n += 1
+
+type
+    r = range[ 0..15 ]
+
+var a: r = 14
+
+++int(a) # this should be mutable
+
+doAssert a == 15
diff --git a/tests/range/toutofrangevarconv.nim b/tests/range/toutofrangevarconv.nim
new file mode 100644
index 000000000..1ee4d340e
--- /dev/null
+++ b/tests/range/toutofrangevarconv.nim
@@ -0,0 +1,14 @@
+discard """
+  outputsub: "value out of range: 5 notin 0 .. 3 [RangeDefect]"
+  exitcode: "1"
+"""
+
+# make sure out of bounds range conversion is detected for `var` conversions
+
+type R = range[0..3]
+
+proc foo(x: var R) =
+  doAssert x in 0..3
+
+var x = 5
+foo(R(x))
diff --git a/tests/refc/tsinkbug.nim b/tests/refc/tsinkbug.nim
new file mode 100644
index 000000000..de2ec98a5
--- /dev/null
+++ b/tests/refc/tsinkbug.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+  output: '''
+Value is: 42
+Value is: 42'''
+"""
+
+type AnObject* = object of RootObj
+  value*: int
+
+proc mutate(a: sink AnObject) =
+  a.value = 1
+
+var obj = AnObject(value: 42)
+echo "Value is: ", obj.value
+mutate(obj)
+echo "Value is: ", obj.value
+
+proc p(x: sink string) = 
+  var y = move(x)
+  doAssert x.len == 0
+  doAssert y.len == 4
+
+p("1234")
+var s = "oooo"
+p(s)
diff --git a/tests/sets/trangeincompatible.nim b/tests/sets/trangeincompatible.nim
new file mode 100644
index 000000000..554a50235
--- /dev/null
+++ b/tests/sets/trangeincompatible.nim
@@ -0,0 +1,32 @@
+block: # issue #20142
+  let
+    s1: set['a' .. 'g'] = {'a', 'e'}
+    s2: set['a' .. 'g'] = {'b', 'c', 'd', 'f'} # this works fine
+    s3 = {'b', 'c', 'd', 'f'}
+
+  doAssert s1 != s2
+  doAssert s1 == {range['a'..'g'] 'a', 'e'}
+  doAssert s2 == {range['a'..'g'] 'b', 'c', 'd', 'f'}
+  # literal conversion:
+  doAssert s1 == {'a', 'e'}
+  doAssert s2 == {'b', 'c', 'd', 'f'}
+  doAssert s3 == {'b', 'c', 'd', 'f'}
+  doAssert not compiles(s1 == s3)
+  doAssert not compiles(s2 == s3)
+  # can't convert literal 'z', overload match fails
+  doAssert not compiles(s1 == {'a', 'z'})
+
+block: # issue #18396
+  var s1: set[char] = {'a', 'b'}
+  var s2: set['a'..'z'] = {'a', 'b'}
+  doAssert s1 == {'a', 'b'}
+  doAssert s2 == {range['a'..'z'] 'a', 'b'}
+  doAssert s2 == {'a', 'b'}
+  doAssert not compiles(s1 == s2)
+
+block: # issue #16270
+  var s1: set[char] = {'a', 'b'}
+  var s2: set['a'..'z'] = {'a', 'c'}
+  doAssert not (compiles do: s2 = s2 + s1)
+  s2 = s2 + {'a', 'b'}
+  doAssert s2 == {'a', 'b', 'c'}
diff --git a/tests/sets/twrongenumrange.nim b/tests/sets/twrongenumrange.nim
new file mode 100644
index 000000000..a8d64ac44
--- /dev/null
+++ b/tests/sets/twrongenumrange.nim
@@ -0,0 +1,50 @@
+discard """
+  cmd: "nim check --hints:off $file"
+"""
+
+# issue #17848
+
+block:
+  # generate with:
+  # var a = ""
+  # for i in 0..<80: a.add "k" & $i & ", "
+  # echo a
+  type
+    TMsgKind = enum
+      k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, k72, k73, k74, k75, k76, k77, k78, k79
+  type
+    TNoteKind = range[k10..k79]
+    Conf = ref object
+      notes: set[TNoteKind]
+  proc bad(conf: Conf, noteSet: set[TMsgKind]) =
+    conf.notes = noteSet #[tt.Error
+                 ^ type mismatch: got <set[TMsgKind]> but expected 'set[TNoteKind]']#
+  var conf = Conf()
+  bad(conf, {k10..k60})
+
+block:
+  type
+    TMsgKind = enum k0, k1, k2, k3
+    TNoteKind = range[k1..k2]
+    TNoteKinds = set[TNoteKind]
+  type Conf = ref object
+    notes: TNoteKinds
+  proc fn(conf: Conf, b: set[TMsgKind]) =
+    conf.notes = b #[tt.Error
+                 ^ type mismatch: got <set[TMsgKind]> but expected 'TNoteKinds = set[TNoteKind]']#
+  var conf = Conf()
+  conf.fn({k0..k3}) # BUG: this should give error
+  echo conf.notes # {k1, k2}
+
+block:
+  #[
+  compiler/bitsets.nim(43, 9) `elem >= 0`  [AssertionDefect]
+  ]#
+  type
+    TMsgKind = enum k0, k1, k2, k3
+    TNoteKind = range[k1..k2]
+  var notes: set[TNoteKind]
+  notes = {k0} #[tt.Error
+          ^ type mismatch: got <set[TMsgKind]> but expected 'set[TNoteKind]']#
+  notes = {k0..k3} #[tt.Error
+          ^ type mismatch: got <set[TMsgKind]> but expected 'set[TNoteKind]']#
diff --git a/tests/stdlib/concurrency/tatomics.nim b/tests/stdlib/concurrency/tatomics.nim
index 3fb5197da..08f2e7d3e 100644
--- a/tests/stdlib/concurrency/tatomics.nim
+++ b/tests/stdlib/concurrency/tatomics.nim
@@ -1,5 +1,7 @@
 discard """
-  matrix: "--mm:refc; --mm:orc"
+  # test C with -d:nimUseCppAtomics as well to check nothing breaks
+  matrix: "--mm:refc; --mm:orc; --mm:refc -d:nimUseCppAtomics; --mm:orc -d:nimUseCppAtomics"
+  targets: "c cpp"
 """
 
 # test atomic operations
diff --git a/tests/stdlib/concurrency/tatomics_size.nim b/tests/stdlib/concurrency/tatomics_size.nim
index cfe568623..f64adb308 100644
--- a/tests/stdlib/concurrency/tatomics_size.nim
+++ b/tests/stdlib/concurrency/tatomics_size.nim
@@ -1,5 +1,6 @@
 discard """
-  matrix: "--mm:refc; --mm:orc"
+  # test C with -d:nimUseCppAtomics as well to check nothing breaks
+  matrix: "--mm:refc; --mm:orc; --mm:refc -d:nimUseCppAtomics; --mm:orc -d:nimUseCppAtomics"
   targets: "c cpp"
 """
 import std/atomics
@@ -17,4 +18,4 @@ block testSize: # issue 12726
       f: AtomicFlag
   static:
     doAssert sizeof(Node) == sizeof(pointer)
-    doAssert sizeof(MyChannel) == sizeof(pointer) * 2
\ No newline at end of file
+    doAssert sizeof(MyChannel) == sizeof(pointer) * 2
diff --git a/tests/stdlib/tcomplex.nim b/tests/stdlib/tcomplex.nim
index 812bcdc77..ca83314b9 100644
--- a/tests/stdlib/tcomplex.nim
+++ b/tests/stdlib/tcomplex.nim
@@ -84,6 +84,9 @@ let t = polar(a)
 doAssert(rect(t.r, t.phi) =~ a)
 doAssert(rect(1.0, 2.0) =~ complex(-0.4161468365471424, 0.9092974268256817))
 
+doAssert(almostEqual(a, a + complex(1e-16, 1e-16)))
+doAssert(almostEqual(a, a + complex(2e-15, 2e-15), unitsInLastPlace = 5))
+
 
 let
   i64: Complex32 = complex(0.0f, 1.0f)
diff --git a/tests/stdlib/tenumutils.nim b/tests/stdlib/tenumutils.nim
index 67b98efe1..2662a660d 100644
--- a/tests/stdlib/tenumutils.nim
+++ b/tests/stdlib/tenumutils.nim
@@ -35,5 +35,15 @@ template main =
     doAssert $b == "kb0"
     static: doAssert B.high.symbolName == "b2"
 
+  block:
+    type
+      Color = enum
+        Red = "red", Yellow = "yellow", Blue = "blue"
+
+    var s = Red
+    doAssert symbolName(s) == "Red"
+    var x: range[Red..Blue] = Yellow
+    doAssert symbolName(x) == "Yellow"
+
 static: main()
 main()
diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim
index b6fbbbdb7..4555fbcb3 100644
--- a/tests/stdlib/thashes.nim
+++ b/tests/stdlib/thashes.nim
@@ -1,5 +1,5 @@
 discard """
-  matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off"
+  matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:on; --backend:c -d:nimStringHash2; --backend:cpp -d:nimStringHash2; --backend:js -d:nimStringHash2"
 """
 
 import std/hashes
@@ -31,7 +31,8 @@ block hashes:
     doAssert hashWangYi1(123) == wy123
     const wyNeg123 = hashWangYi1(-123)
     doAssert wyNeg123 != 0
-    doAssert hashWangYi1(-123) == wyNeg123
+    when not defined(js): # TODO: fixme it doesn't work for JS
+      doAssert hashWangYi1(-123) == wyNeg123
 
 
   # "hashIdentity value incorrect at 456"
@@ -45,20 +46,31 @@ block hashes:
     else:
       doAssert hashWangYi1(456) == -6421749900419628582
 
+template jsNoInt64: untyped =
+  when defined js:
+    when compiles(compileOption("jsbigint64")):
+      when not compileOption("jsbigint64"): true
+      else: false
+    else: false
+  else: false
+const sHash2 = (when defined(nimStringHash2) or jsNoInt64(): true else: false)
+
 block empty:
+  const emptyStrHash = # Hash=int=4B on js even w/--jsbigint64:on => cast[Hash]
+    when sHash2: 0 else: cast[Hash](-7286425919675154353i64)
   var
     a = ""
     b = newSeq[char]()
     c = newSeq[int]()
     d = cstring""
     e = "abcd"
-  doAssert hash(a) == 0
-  doAssert hash(b) == 0
+  doAssert hash(a) == emptyStrHash
+  doAssert hash(b) == emptyStrHash
   doAssert hash(c) == 0
-  doAssert hash(d) == 0
+  doAssert hash(d) == emptyStrHash
   doAssert hashIgnoreCase(a) == 0
   doAssert hashIgnoreStyle(a) == 0
-  doAssert hash(e, 3, 2) == 0
+  doAssert hash(e, 3, 2) == emptyStrHash
 
 block sameButDifferent:
   doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13)
@@ -92,7 +104,10 @@ block largeSize: # longer than 4 characters
 proc main() =
   doAssert hash(0.0) == hash(0)
   # bug #16061
-  doAssert hash(cstring"abracadabra") == 97309975
+  when not sHash2: # Hash=int=4B on js even w/--jsbigint64:on => cast[Hash]
+    doAssert hash(cstring"abracadabra") == cast[Hash](-1119910118870047694i64)
+  else:
+    doAssert hash(cstring"abracadabra") == 97309975
   doAssert hash(cstring"abracadabra") == hash("abracadabra")
 
   when sizeof(int) == 8 or defined(js):
diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim
index 00e728fa2..0bd479670 100644
--- a/tests/stdlib/thttpclient.nim
+++ b/tests/stdlib/thttpclient.nim
@@ -53,9 +53,9 @@ proc asyncTest() {.async.} =
   doAssert("<title>Example Domain</title>" in body)
 
   resp = await client.request("http://example.com/404")
-  doAssert(resp.code.is4xx)
-  doAssert(resp.code == Http404)
-  doAssert(resp.status == $Http404)
+  doAssert(resp.code.is4xx or resp.code.is5xx)
+  doAssert(resp.code == Http404 or resp.code == Http500)
+  doAssert(resp.status == $Http404 or resp.status == $Http500)
 
   when false: # occasionally does not give success code 
     resp = await client.request("https://google.com/")
@@ -115,9 +115,9 @@ proc syncTest() =
   doAssert("<title>Example Domain</title>" in resp.body)
 
   resp = client.request("http://example.com/404")
-  doAssert(resp.code.is4xx)
-  doAssert(resp.code == Http404)
-  doAssert(resp.status == $Http404)
+  doAssert(resp.code.is4xx or resp.code.is5xx)
+  doAssert(resp.code == Http404 or resp.code == Http500)
+  doAssert(resp.status == $Http404 or resp.status == $Http500)
 
   when false: # occasionally does not give success code
     resp = client.request("https://google.com/")
diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim
index feacd3e57..6b963f029 100644
--- a/tests/stdlib/thttpclient_ssl.nim
+++ b/tests/stdlib/thttpclient_ssl.nim
@@ -13,7 +13,10 @@ discard """
 ## Test with:
 ## ./bin/nim c -d:ssl -p:. --threads:on -r tests/stdlib/thttpclient_ssl.nim
 
-when not defined(windows):
+
+from stdtest/testutils import disableSSLTesting
+
+when not defined(windows) and not disableSSLTesting():
   # Disabled on Windows due to old OpenSSL version
   import std/[formatfloat, syncio]
   import
diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim
index 691bedeaa..e425501f6 100644
--- a/tests/stdlib/tjson.nim
+++ b/tests/stdlib/tjson.nim
@@ -1,5 +1,5 @@
 discard """
-  matrix: "--mm:refc; --backend:cpp --mm:refc; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on"
+  matrix: "; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
 """
 
 
@@ -51,7 +51,7 @@ for i in 0 .. 10000:
   except:
     discard
 # memory diff should less than 4M
-doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024) # todo fixme doesn;t work for ORC
+doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024)
 
 
 # test `$`
diff --git a/tests/stdlib/tmarshalsegfault.nim b/tests/stdlib/tmarshalsegfault.nim
new file mode 100644
index 000000000..71f2766c8
--- /dev/null
+++ b/tests/stdlib/tmarshalsegfault.nim
@@ -0,0 +1,54 @@
+# issue #12405
+
+import std/[marshal, streams, times, tables, os, assertions]
+
+type AiredEpisodeState * = ref object
+    airedAt * : DateTime
+    tvShowId * : string
+    seasonNumber * : int
+    number * : int
+    title * : string
+
+type ShowsWatchlistState * = ref object
+    aired * : seq[AiredEpisodeState]
+
+type UiState * = ref object
+    shows: ShowsWatchlistState
+
+# Helpers to marshal and unmarshal
+proc load * ( state : var UiState, file : string ) =
+    var strm = newFileStream( file, fmRead )
+
+    strm.load( state )
+
+    strm.close()
+
+proc store * ( state : UiState, file : string ) =
+    var strm = newFileStream( file, fmWrite )
+
+    strm.store( state )
+
+    strm.close()
+
+# 1. We fill the state initially
+var state : UiState = UiState( shows: ShowsWatchlistState( aired: @[] ) )
+
+# VERY IMPORTANT: For some reason, small numbers (like 2 or 3) don't trigger the bug. Anything above 7 or 8 on my machine triggers though
+for i in 0..30:
+    var episode = AiredEpisodeState( airedAt: now(), tvShowId: "1", seasonNumber: 1, number: 1, title: "string" )
+
+    state.shows.aired.add( episode )
+
+# 2. Store it in a file with the marshal module, and then load it back up
+store( state, "tmarshalsegfault_data" )
+load( state, "tmarshalsegfault_data" )
+removeFile("tmarshalsegfault_data")
+
+# 3. VERY IMPORTANT: Without this line, for some reason, everything works fine
+state.shows.aired[ 0 ] = AiredEpisodeState( airedAt: now(), tvShowId: "1", seasonNumber: 1, number: 1, title: "string" )
+
+# 4. And formatting the airedAt date will now trigger the exception
+for ep in state.shows.aired:
+    let x = $ep.seasonNumber & "x" & $ep.number & " (" & $ep.airedAt & ")"
+    let y = $ep.seasonNumber & "x" & $ep.number & " (" & $ep.airedAt & ")"
+    doAssert x == y
diff --git a/tests/stdlib/tmimetypes.nim b/tests/stdlib/tmimetypes.nim
index 372a8f3d8..fd66ebd97 100644
--- a/tests/stdlib/tmimetypes.nim
+++ b/tests/stdlib/tmimetypes.nim
@@ -19,5 +19,10 @@ template main() =
   # see also `runnableExamples`.
   # xxx we should have a way to avoid duplicating code between runnableExamples and tests
 
+  doAssert m.getMimetype("nim") == "text/nim"
+  doAssert m.getMimetype("nimble") == "text/nimble"
+  doAssert m.getMimetype("nimf") == "text/nim"
+  doAssert m.getMimetype("nims") == "text/nim"
+
 static: main()
 main()
diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim
index ad34e479a..611659fdb 100644
--- a/tests/stdlib/tos.nim
+++ b/tests/stdlib/tos.nim
@@ -27,9 +27,8 @@ Raises
 """
 # test os path creation, iteration, and deletion
 
-import os, strutils, pathnorm
 from stdtest/specialpaths import buildDir
-import std/[syncio, assertions]
+import std/[syncio, assertions, osproc, os, strutils, pathnorm]
 
 block fileOperations:
   let files = @["these.txt", "are.x", "testing.r", "files.q"]
@@ -161,6 +160,18 @@ block fileOperations:
   # createDir should not fail if `dir` is empty
   createDir("")
 
+
+  when defined(linux): # bug #24174
+    createDir("a/b")
+    open("a/file.txt", fmWrite).close
+
+    if not fileExists("a/fifoFile"):
+      doAssert execCmd("mkfifo -m 600 a/fifoFile") == 0
+
+    copyDir("a/", "../dest/a/", skipSpecial = true)
+    copyDirWithPermissions("a/", "../dest2/a/", skipSpecial = true)
+    removeDir("a")
+
   # Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`,
   # `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`.
   block:
diff --git a/tests/stdlib/tparseutils.nim b/tests/stdlib/tparseutils.nim
index 020964446..b69900864 100644
--- a/tests/stdlib/tparseutils.nim
+++ b/tests/stdlib/tparseutils.nim
@@ -99,3 +99,14 @@ block:  # With this included, static: test() crashes the compiler (from a
   checkParseSize " 12"    , 0, 1          # Leading white
   # Value Edge cases
   checkParseSize "9223372036854775807", 19, int64.high
+
+block: # bug #23936
+  func parsePyFloat(
+      a: openArray[char],  # here must be openArray instead of string to reproduce this bug
+      res: var BiggestFloat): int =
+    result = parseFloat(a, res)
+
+  static:
+    var f = 0.0
+    doAssert "1.0".parsePyFloat(f) == 3
+    doAssert f == 1.0
diff --git a/tests/stdlib/tpaths.nim b/tests/stdlib/tpaths.nim
index 082c4937a..edb56209a 100644
--- a/tests/stdlib/tpaths.nim
+++ b/tests/stdlib/tpaths.nim
@@ -6,15 +6,12 @@ import std/paths
 import std/assertions
 import pathnorm
 from std/private/ospaths2 {.all.} import joinPathImpl
-import std/sugar
+import std/[sugar, sets]
 
 
 proc normalizePath*(path: Path; dirSep = DirSep): Path =
   result = Path(pathnorm.normalizePath(path.string, dirSep))
 
-func `==`(x, y: Path): bool =
-  x.string == y.string
-
 func joinPath*(parts: varargs[Path]): Path =
   var estimatedLen = 0
   var state = 0
@@ -231,4 +228,11 @@ block ospaths:
   when doslikeFileSystem:
     doAssert joinPath(Path"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", Path"..\\..\\VC\\vcvarsall.bat") == r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat".Path
     doAssert joinPath(Path"C:\\foo", Path"..\\a") == r"C:\a".Path
-    doAssert joinPath(Path"C:\\foo\\", Path"..\\a") == r"C:\a".Path
\ No newline at end of file
+    doAssert joinPath(Path"C:\\foo\\", Path"..\\a") == r"C:\a".Path
+
+
+block: # bug #23663
+  var s: HashSet[Path]
+  s.incl("/a/b/c/..".Path)
+  doAssert "/a/b/".Path in s
+  doAssert "/a/b/c".Path notin s
diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim
index 920d429d4..eb32f7757 100644
--- a/tests/stdlib/trandom.nim
+++ b/tests/stdlib/trandom.nim
@@ -1,6 +1,6 @@
 discard """
   joinable: false # to avoid messing with global rand state
-  matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on"
+  matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
 """
 import std/[assertions, formatfloat]
 import std/[random, math, stats, sets, tables]
@@ -47,6 +47,8 @@ block:
   type DiceRoll = range[0..6]
   when not defined(js):
     doAssert rand(DiceRoll).int == 3
+  elif compileOption("jsbigint64"):
+    doAssert rand(DiceRoll).int == 1
   else:
     doAssert rand(DiceRoll).int == 6
 
@@ -296,7 +298,13 @@ block: # bug #22360
     else:
       inc fc
 
-  when defined(js):
-    doAssert (tc, fc) == (483, 517), $(tc, fc)
+  when defined(js) and not compileOption("jsbigint64"):
+    doAssert (tc, fc) == (515, 485), $(tc, fc)
   else:
     doAssert (tc, fc) == (510, 490), $(tc, fc)
+
+block:
+  when defined(js) and not compileOption("jsbigint64"):
+    doAssert rand(int32.high) == 335507522
+  else:
+    doAssert rand(int32.high) == 607539621
diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim
index e39eae9c1..ceab34bc9 100644
--- a/tests/stdlib/trst.nim
+++ b/tests/stdlib/trst.nim
@@ -16,6 +16,8 @@ discard """
 [Suite] RST escaping
 
 [Suite] RST inline markup
+
+[Suite] Misc isssues
 '''
 matrix: "--mm:refc; --mm:orc"
 """
@@ -526,8 +528,7 @@ suite "RST parsing":
             rnFieldBody
               rnLeaf  'Nim'
         rnLiteralBlock
-          rnLeaf  '
-      let a = 1
+          rnLeaf  'let a = 1
       ```'
       """
 
@@ -637,8 +638,7 @@ suite "RST parsing":
                 rnLeaf  'test'
               rnFieldBody
           rnLiteralBlock
-            rnLeaf  '
-        let a = 1'
+            rnLeaf  'let a = 1'
         """)
 
     check(dedent"""
@@ -661,8 +661,7 @@ suite "RST parsing":
               rnFieldBody
                 rnLeaf  '1'
           rnLiteralBlock
-            rnLeaf  '
-        let a = 1'
+            rnLeaf  'let a = 1'
         """)
 
   test "additional indentation < 4 spaces is handled fine":
@@ -682,8 +681,7 @@ suite "RST parsing":
                 rnLeaf  'nim'
               [nil]
               rnLiteralBlock
-                rnLeaf  '
-          let a = 1'
+                rnLeaf  '  let a = 1'
       """)
       # | |
       # |  \ indentation of exactly two spaces before 'let a = 1'
@@ -717,8 +715,7 @@ suite "RST parsing":
                   rnFieldBody
                     rnLeaf  'Nim'
               rnLiteralBlock
-                rnLeaf  '
-        CodeBlock()'
+                rnLeaf  'CodeBlock()'
             rnLeaf  ' '
             rnLeaf  'Other'
             rnLeaf  ' '
@@ -1985,3 +1982,13 @@ suite "RST inline markup":
           rnLeaf  ')'
       """)
     check(warnings[] == @["input(1, 5) Warning: broken link 'f'"])
+
+suite "Misc isssues":
+  test "Markdown CodeblockFields in one line (lacking enclosing ```)":
+    let message = """
+    ```llvm-profdata merge first.profraw second.profraw third.profraw <more stuff maybe> -output data.profdata```"""
+
+    try:
+      echo rstgen.rstToHtml(message, {roSupportMarkdown}, nil)
+    except EParseError:
+      discard
diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim
index 934403665..6253e7146 100644
--- a/tests/stdlib/trstgen.nim
+++ b/tests/stdlib/trstgen.nim
@@ -1246,7 +1246,7 @@ Test1
         "input(8, 4) Warning: language 'anotherLang' not supported"
         ])
     check(output == "<pre class = \"listing\">anything</pre>" &
-                    "<p><pre class = \"listing\">\nsomeCode</pre> </p>")
+                    "<p><pre class = \"listing\">someCode</pre> </p>")
 
   test "RST admonitions":
     # check that all admonitions are implemented
diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim
index 0668d12bd..60c63b450 100644
--- a/tests/stdlib/tstreams.nim
+++ b/tests/stdlib/tstreams.nim
@@ -92,6 +92,10 @@ static: # Ensure streams it doesnt break with nimscript on arc/orc #19716
   let s = newStringStream("a")
   doAssert s.data == "a"
 
+static: # issue #24054, readStr
+  var s = newStringStream("foo bar baz")
+  doAssert s.readStr(3) == "foo"
+
 template main =
   var strm = newStringStream("abcde")
   var buffer = "12345"
diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim
index 9cc65f218..35f6bc669 100644
--- a/tests/stdlib/tstrutils.nim
+++ b/tests/stdlib/tstrutils.nim
@@ -1,5 +1,5 @@
 discard """
-  matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on"
+  matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
 """
 
 import std/strutils
@@ -527,9 +527,9 @@ template main() =
 
   block: # toHex
     doAssert(toHex(100i16, 32) == "00000000000000000000000000000064")
-    doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C")
     whenJsNoBigInt64: discard
     do:
+      doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C")
       doAssert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF")
       doAssert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF")
       doAssert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF")
diff --git a/tests/stdlib/tsystem.nim b/tests/stdlib/tsystem.nim
index c1cadb49d..f634ce0c2 100644
--- a/tests/stdlib/tsystem.nim
+++ b/tests/stdlib/tsystem.nim
@@ -4,7 +4,7 @@ discard """
 """
 
 import stdtest/testutils
-import std/assertions
+import std/[assertions, formatfloat]
 
 # TODO: in future work move existing `system` tests here, where they belong
 
@@ -83,24 +83,36 @@ block:
     X = object
       a: string
       b: set[char]
+      c: int
+      d: float
+      e: int64
 
-  var y = X(b: {'a'})
 
-  reset(y)
+  var x = X(b: {'a'}, e: 10)
 
-  doAssert y.b == {}
+  var y = move x
 
-block:
-  type
-    X = object
-      a: string
-      b: int
-
-  var y = X(b: 1314)
+  doAssert x.a == ""
+  doAssert x.b == {}
+  doAssert x.c == 0
+  doAssert x.d == 0.0
+  doAssert x.e == 0
 
   reset(y)
 
-  doAssert y.b == 0
+  doAssert y.a == ""
+  doAssert y.b == {}
+  doAssert y.c == 0
+  doAssert y.d == 0.0
+  doAssert y.e == 0
+
+block:
+  var x = 2
+  var y = move x
+  doAssert y == 2
+  doAssert x == 0
+  reset y
+  doAssert y == 0
 
 block:
   type
@@ -170,3 +182,19 @@ block: # bug #20516
 
   when not defined(js):
     let a = create(Foo)
+
+block: # bug #6549
+  when not defined(js):
+    block:
+      const v = 18446744073709551615'u64
+
+      doAssert $v == "18446744073709551615"
+      doAssert $float32(v) == "1.8446744e+19", $float32(v)
+      doAssert $float64(v) == "1.8446744073709552e+19", $float64(v)
+
+    block:
+      let v = 18446744073709551615'u64
+
+      doAssert $v == "18446744073709551615"
+      doAssert $float32(v) == "1.8446744e+19"
+      doAssert $float64(v) == "1.8446744073709552e+19"
diff --git a/tests/stdlib/ttasks.nim b/tests/stdlib/ttasks.nim
index 347c3347a..ba65590d9 100644
--- a/tests/stdlib/ttasks.nim
+++ b/tests/stdlib/ttasks.nim
@@ -523,3 +523,39 @@ block:
       doAssert resB == "abcdef"
 
     testReturnValues()
+
+
+block: # bug #23635
+  block:
+    type
+      Store = object
+        run: proc (a: int) {.nimcall, gcsafe.}
+
+    block:
+      var count = 0
+      proc hello(a: int) =
+        inc count, a
+
+      var store = Store()
+      store.run = hello
+
+      let b = toTask store.run(13)
+      b.invoke()
+      doAssert count == 13
+
+  block:
+    type
+      Store = object
+        run: proc () {.nimcall, gcsafe.}
+
+    block:
+      var count = 0
+      proc hello() =
+        inc count, 1
+
+      var store = Store()
+      store.run = hello
+
+      let b = toTask store.run()
+      b.invoke()
+      doAssert count == 1
diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim
index e01ab3a4f..0f04168dc 100644
--- a/tests/stdlib/ttimes.nim
+++ b/tests/stdlib/ttimes.nim
@@ -1,5 +1,5 @@
 discard """
-  matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off"
+  matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off -d:nimStringHash2"
 """
 
 import times, strutils, unittest
@@ -71,7 +71,7 @@ template runTimezoneTests() =
       "2006-01-12T22:04:05Z", 11)
   # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
   parseTest("2006-01-12T15:04:05.999999999Z-07:00",
-      "yyyy-MM-dd'T'HH:mm:ss'.999999999Z'zzz", "2006-01-12T22:04:05Z", 11)
+      "yyyy-MM-dd'T'HH:mm:ss.'999999999Z'zzz", "2006-01-12T22:04:05Z", 11)
   for tzFormat in ["z", "zz", "zzz"]:
     # formatting timezone as 'Z' for UTC
     parseTest("2001-01-12T22:04:05Z", "yyyy-MM-dd'T'HH:mm:ss" & tzFormat,
@@ -770,3 +770,15 @@ block: # ttimes
     proc test(): DateTime {.gcsafe.} =
       result = "1970".parse("yyyy")
     doAssert test().year == 1970
+
+  block: # test FormatLiterals
+    # since #23861
+    block:
+      let dt = dateTime(2024, mJul, 21, 17, 01, 02, 123_321_123, utc())
+      check dt.format("ss.fff") == "02.123"
+      check dt.format("fff.ffffff") == "123.123321"
+    block:
+      let dt = parse("2024.07.21", "yyyy.MM.dd")
+      check dt.year == 2024
+      check dt.month == mJul
+      check dt.monthday == 21
diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim
index 8d5061124..9bbc2e92c 100644
--- a/tests/stdlib/ttypeinfo.nim
+++ b/tests/stdlib/ttypeinfo.nim
@@ -74,3 +74,20 @@ block:
 
   doAssert getEnumOrdinal(y, "Hello") == 0
   doAssert getEnumOrdinal(y, "hello") == 1
+
+block: # bug #23556
+  proc test =
+    var
+      t: seq[int]
+      aseq = toAny(t)
+
+    invokeNewSeq(aseq, 0)
+
+    # Got random value only when loop 8 times.
+    for i in 1 .. 8:
+      extendSeq(aseq)
+
+    doAssert t == @[0, 0, 0, 0, 0, 0, 0, 0]
+
+  for i in 1 .. 7:
+    test()
diff --git a/tests/stdlib/tunicode.nim b/tests/stdlib/tunicode.nim
index adc8d2078..b9e68b15b 100644
--- a/tests/stdlib/tunicode.nim
+++ b/tests/stdlib/tunicode.nim
@@ -57,6 +57,7 @@ doAssert isAlpha("r")
 doAssert isAlpha("α")
 doAssert isAlpha("ϙ")
 doAssert isAlpha("ஶ")
+doAssert isAlpha("网")
 doAssert(not isAlpha("$"))
 doAssert(not isAlpha(""))
 
@@ -66,6 +67,7 @@ doAssert isAlpha("𐌼𐌰𐌲𐌲𐌻𐌴𐍃𐍄𐌰𐌽")
 doAssert isAlpha("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει")
 doAssert isAlpha("Јамогујестистаклоитоминештети")
 doAssert isAlpha("Կրնամապակիուտեևինծիանհանգիստչըներ")
+doAssert isAlpha("编程语言")
 doAssert(not isAlpha("$Foo✓"))
 doAssert(not isAlpha("⠙⠕⠑⠎⠝⠞"))
 
diff --git a/tests/stdlib/tunixsocket.nim b/tests/stdlib/tunixsocket.nim
new file mode 100644
index 000000000..636fd08c6
--- /dev/null
+++ b/tests/stdlib/tunixsocket.nim
@@ -0,0 +1,35 @@
+import std/[assertions, net, os, osproc]
+
+# XXX: Make this test run on Windows too when we add support for Unix sockets on Windows
+when defined(posix) and not defined(nimNetLite):
+  const nim = getCurrentCompilerExe()
+  let
+    dir = currentSourcePath().parentDir()
+    serverPath = dir / "unixsockettest"
+
+  let (_, err) = execCmdEx(nim & " c " & quoteShell(dir / "unixsockettest.nim"))
+  doAssert err == 0
+
+  let svproc = startProcess(serverPath, workingDir = dir)
+  doAssert svproc.running()
+  # Wait for the server to open the socket and listen from it
+  sleep(400)
+
+  block unixSocketSendRecv:
+    let
+      unixSocketPath = dir / "usox"
+      socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_NONE)
+
+    socket.connectUnix(unixSocketPath)
+    # for a blocking Unix socket this should never fail
+    socket.send("data sent through the socket\c\l", maxRetries = 0)
+    var resp: string
+    socket.readLine(resp)
+    doAssert resp == "Hello from server"
+
+    socket.send("bye\c\l")
+    socket.readLine(resp)
+    doAssert resp == "bye"
+    socket.close()
+
+  svproc.close()
diff --git a/tests/stdlib/tvarints.nim b/tests/stdlib/tvarints.nim
index 35f1cd849..f9624ee5b 100644
--- a/tests/stdlib/tvarints.nim
+++ b/tests/stdlib/tvarints.nim
@@ -33,7 +33,7 @@ block:
     doAssert cast[float64](got) == test
 
 block:
-  var hugeIntArray: array[50, byte]
+  var hugeIntArray: array[9, byte]
   var readedInt: uint64
 
   template chk(a) =
diff --git a/tests/stdlib/tvolatile.nim b/tests/stdlib/tvolatile.nim
new file mode 100644
index 000000000..c097f9723
--- /dev/null
+++ b/tests/stdlib/tvolatile.nim
@@ -0,0 +1,15 @@
+import std/[volatile, assertions]
+
+var st: int
+var foo: ptr int = addr st
+volatileStore(foo, 12)
+doAssert volatileLoad(foo) == 12
+
+# bug #14623
+proc bar =
+  var st: int
+  var foo: ptr int = addr st
+  volatileStore(foo, 12)
+  doAssert volatileLoad(foo) == 12
+
+bar()
diff --git a/tests/stdlib/twrongstattype.nim b/tests/stdlib/twrongstattype.nim
new file mode 100644
index 000000000..4a1fc30c6
--- /dev/null
+++ b/tests/stdlib/twrongstattype.nim
@@ -0,0 +1,14 @@
+# issue #24076
+
+when defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
+  import std/posix
+  proc uid(x: uint32): Uid = Uid(x)
+  var y: uint32
+  let myUid = geteuid()
+  discard myUid == uid(y)
+  proc dev(x: uint32): Dev = Dev(x)
+  let myDev = 1.Dev
+  discard myDev == dev(y)
+  proc nlink(x: uint32): Nlink = Nlink(x)
+  let myNlink = 1.Nlink
+  discard myNlink == nlink(y)
diff --git a/tests/stdlib/unixsockettest.nim b/tests/stdlib/unixsockettest.nim
new file mode 100644
index 000000000..8f95d0808
--- /dev/null
+++ b/tests/stdlib/unixsockettest.nim
@@ -0,0 +1,26 @@
+import std/[assertions, net, os]
+
+let unixSocketPath = getCurrentDir() / "usox"
+
+removeFile(unixSocketPath)
+
+let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_NONE)
+socket.bindUnix(unixSocketPath)
+socket.listen()
+
+var
+  clientSocket: Socket
+  data: string
+
+socket.accept(clientSocket)
+clientSocket.readLine(data)
+doAssert data == "data sent through the socket"
+clientSocket.send("Hello from server\c\l")
+
+clientSocket.readLine(data)
+doAssert data == "bye"
+clientSocket.send("bye\c\l")
+
+clientSocket.close()
+socket.close()
+removeFile(unixSocketPath)
diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim
index 39337cca7..eabee81b3 100644
--- a/tests/system/tdollars.nim
+++ b/tests/system/tdollars.nim
@@ -1,5 +1,5 @@
 discard """
-  matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on"
+  matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
 """
 
 #[
@@ -109,10 +109,10 @@ block:
     # if `uint8(a1)` changes meaning to `cast[uint8](a1)` in future, update this test;
     # until then, this is the correct semantics.
     let a3 = $a2
-    doAssert a2 < 3
-    doAssert a3 == "-1"
+    doAssert a2 == 255'u8
+    doAssert a3 == "255"
     proc intToStr(a: uint8): cstring {.importjs: "(# + \"\")".}
-    doAssert $intToStr(a2) == "-1"
+    doAssert $intToStr(a2) == "255"
   else:
     block:
       let x = -1'i8
diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim
index c8e2b2a9d..1debb7c48 100644
--- a/tests/system/tsystem_misc.nim
+++ b/tests/system/tsystem_misc.nim
@@ -219,3 +219,9 @@ proc bug23223 = # bug #23223
   doAssert stuff == "hello"
 
 bug23223()
+
+block: # bug #23894
+  let v = high(uint) div 2
+  let s = v + 1 # 9223372036854775808
+  let m = succ v
+  doAssert s == m
diff --git a/tests/template/m19277_1.nim b/tests/template/m19277_1.nim
new file mode 100644
index 000000000..840bd4767
--- /dev/null
+++ b/tests/template/m19277_1.nim
@@ -0,0 +1,2 @@
+template foo*(x: untyped) =
+  echo "got: ", x
diff --git a/tests/template/m19277_2.nim b/tests/template/m19277_2.nim
new file mode 100644
index 000000000..de72dad45
--- /dev/null
+++ b/tests/template/m19277_2.nim
@@ -0,0 +1,2 @@
+proc foo*(a: string) =
+  echo "got string: ", a
diff --git a/tests/template/mqualifiedtype1.nim b/tests/template/mqualifiedtype1.nim
new file mode 100644
index 000000000..46569107f
--- /dev/null
+++ b/tests/template/mqualifiedtype1.nim
@@ -0,0 +1,2 @@
+type A* = object
+  x*: int
diff --git a/tests/template/mqualifiedtype2.nim b/tests/template/mqualifiedtype2.nim
new file mode 100644
index 000000000..6a61c14bd
--- /dev/null
+++ b/tests/template/mqualifiedtype2.nim
@@ -0,0 +1,2 @@
+type A* = object
+  x*: array[1000, byte]
diff --git a/tests/template/t13426.nim b/tests/template/t13426.nim
new file mode 100644
index 000000000..f7f44749c
--- /dev/null
+++ b/tests/template/t13426.nim
@@ -0,0 +1,87 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  errormsg: ""
+  nimout: '''
+t13426.nim(81, 6) template/generic instantiation of `fun` from here
+t13426.nim(80, 24) Error: type mismatch: got <int> but expected 'string'
+t13426.nim(81, 6) template/generic instantiation of `fun` from here
+t13426.nim(80, 17) Error: type mismatch: got <uint, string>
+but expected one of:
+proc `and`(x, y: uint): uint
+  first type mismatch at position: 2
+  required type for y: uint
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint64): uint64
+  first type mismatch at position: 2
+  required type for y: uint64
+  but expression 'high(@[1])' is of type: string
+10 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
+
+expression: 1'u and high(@[1])
+t13426.nim(81, 6) template/generic instantiation of `fun` from here
+t13426.nim(80, 17) Error: expression '' has no type (or is ambiguous)
+t13426.nim(87, 6) template/generic instantiation of `fun` from here
+t13426.nim(86, 22) Error: type mismatch: got <int> but expected 'string'
+t13426.nim(87, 6) template/generic instantiation of `fun` from here
+t13426.nim(86, 15) Error: type mismatch: got <int literal(1), string>
+but expected one of:
+proc `and`(x, y: int): int
+  first type mismatch at position: 2
+  required type for y: int
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: int16): int16
+  first type mismatch at position: 2
+  required type for y: int16
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: int32): int32
+  first type mismatch at position: 2
+  required type for y: int32
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: int64): int64
+  first type mismatch at position: 2
+  required type for y: int64
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: int8): int8
+  first type mismatch at position: 2
+  required type for y: int8
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint): uint
+  first type mismatch at position: 2
+  required type for y: uint
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint16): uint16
+  first type mismatch at position: 2
+  required type for y: uint16
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint32): uint32
+  first type mismatch at position: 2
+  required type for y: uint32
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint64): uint64
+  first type mismatch at position: 2
+  required type for y: uint64
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint8): uint8
+  first type mismatch at position: 2
+  required type for y: uint8
+  but expression 'high(@[1])' is of type: string
+2 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
+
+expression: 1 and high(@[1])
+t13426.nim(87, 6) template/generic instantiation of `fun` from here
+t13426.nim(86, 15) Error: expression '' has no type (or is ambiguous)
+'''
+"""
+
+# bug # #13426
+block:
+  template bar(t): string = high(t)
+  proc fun[A](key: A) =
+    var h = 1'u and bar(@[1])
+  fun(0)
+
+block:
+  template bar(t): string = high(t)
+  proc fun[A](key: A) =
+    var h = 1 and bar(@[1])
+  fun(0)
diff --git a/tests/template/t19277.nim b/tests/template/t19277.nim
new file mode 100644
index 000000000..16435a09c
--- /dev/null
+++ b/tests/template/t19277.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''
+got: 0
+'''
+"""
+
+# issue #19277
+
+import m19277_1, m19277_2
+
+template injector(val: untyped): untyped =
+  template subtemplate: untyped = val
+  subtemplate()
+
+template methodCall(val: untyped): untyped = val
+
+{.push raises: [Defect].}
+
+foo(injector(0).methodCall())
diff --git a/tests/template/t24112.nim b/tests/template/t24112.nim
new file mode 100644
index 000000000..175fc7d5e
--- /dev/null
+++ b/tests/template/t24112.nim
@@ -0,0 +1,19 @@
+discard """
+  matrix: "--skipParentCfg --filenames:legacyRelProj --hints:off"
+  action: reject
+"""
+
+# issue #24112, needs --experimental:openSym disabled
+
+block: # simplified
+  type
+    SomeObj = ref object # Doesn't error if you make SomeObj be non-ref
+  template foo = yield SomeObj()
+  when compiles(foo): discard
+
+import std/asyncdispatch
+block:
+  proc someProc(): Future[void] {.async.} = discard
+  proc foo() =
+    await someProc() #[tt.Error
+                  ^ Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead]#
diff --git a/tests/template/tdefaultparam.nim b/tests/template/tdefaultparam.nim
new file mode 100644
index 000000000..7ea0b2b25
--- /dev/null
+++ b/tests/template/tdefaultparam.nim
@@ -0,0 +1,56 @@
+block:
+  template foo(a: untyped, b: untyped = a(0)): untyped =
+    let x = a(0)
+    let y = b
+    (x, y)
+  proc bar(x: int): int = x + 1
+  doAssert foo(bar, b = bar(0)) == (1, 1)
+  doAssert foo(bar) == (1, 1)
+
+block: # issue #23506
+  var a: string
+  template foo(x: int; y = x) =
+    a = $($x, $y)
+  foo(1)
+  doAssert a == "(\"1\", \"1\")"
+
+block: # untyped params with default value
+  macro foo(x: typed): untyped =
+    result = x
+  template test(body: untyped, alt: untyped = (;), maxTries = 3): untyped {.foo.} =
+    body
+    alt
+  var s = "a"
+  test:
+    s.add "b"
+  do:
+    s.add "c"
+  doAssert s == "abc"
+  template test2(body: untyped, alt: untyped = s.add("e"), maxTries = 3): untyped =
+    body
+    alt
+  test2:
+    s.add "d"
+  doAssert s == "abcde"
+  template test3(body: untyped = willNotCompile) =
+    discard
+  test3()
+
+block: # typed params with `void` default value
+  macro foo(x: typed): untyped =
+    result = x
+  template test(body: untyped, alt: typed = (;), maxTries = 3): untyped {.foo.} =
+    body
+    alt
+  var s = "a"
+  test:
+    s.add "b"
+  do:
+    s.add "c"
+  doAssert s == "abc"
+  template test2(body: untyped, alt: typed = s.add("e"), maxTries = 3): untyped =
+    body
+    alt
+  test2:
+    s.add "d"
+  doAssert s == "abcde"
diff --git a/tests/template/tinnerouterproc.nim b/tests/template/tinnerouterproc.nim
index 1f15fb13e..56e0d02df 100644
--- a/tests/template/tinnerouterproc.nim
+++ b/tests/template/tinnerouterproc.nim
@@ -6,3 +6,15 @@ block: # #20002
     discard 3.bar # evaluates to 10 but only check if it compiles for now
   block:
     foo()
+
+block: # issue #23813
+  template r(body: untyped) =
+    proc x() {.gensym.} =
+      body
+  template g() =
+    r:
+      let y = 0
+    r:
+      proc y() = discard
+      y()
+  g()
diff --git a/tests/template/topensym.nim b/tests/template/topensym.nim
new file mode 100644
index 000000000..2f930407b
--- /dev/null
+++ b/tests/template/topensym.nim
@@ -0,0 +1,209 @@
+{.experimental: "openSym".}
+
+block: # issue #24002
+  type Result[T, E] = object
+  func value[T, E](self: Result[T, E]): T {.inline.} =
+    discard
+  func value[T: not void, E](self: var Result[T, E]): var T {.inline.} =
+    discard
+  template unrecognizedFieldWarning =
+    doAssert value == 123
+    let x = value
+    doAssert value == x
+  proc readValue(value: var int) =
+    unrecognizedFieldWarning()
+  var foo: int = 123
+  readValue(foo)
+
+block: # issue #22605 for templates, normal call syntax
+  const error = "bad"
+
+  template valueOr(self: int, def: untyped): untyped =
+    case false
+    of true: ""
+    of false:
+      template error: untyped {.used, inject.} = "good"
+      def
+
+  template g(T: type): string =
+    var res = "ok"
+    let x = valueOr 123:
+      res = $error
+      "dummy"
+    res
+
+  doAssert g(int) == "good"
+
+  template g2(T: type): string =
+    bind error # use the bad version on purpose
+    var res = "ok"
+    let x = valueOr 123:
+      res = $error
+      "dummy"
+    res
+
+  doAssert g2(int) == "bad"
+
+block: # issue #22605 for templates, method call syntax
+  const error = "bad"
+
+  template valueOr(self: int, def: untyped): untyped =
+    case false
+    of true: ""
+    of false:
+      template error: untyped {.used, inject.} = "good"
+      def
+
+  template g(T: type): string =
+    var res = "ok"
+    let x = 123.valueOr:
+      res = $error
+      "dummy"
+    res
+
+  doAssert g(int) == "good"
+
+  template g2(T: type): string =
+    bind error # use the bad version on purpose
+    var res = "ok"
+    let x = 123.valueOr:
+      res = $error
+      "dummy"
+    res
+
+  doAssert g2(int) == "bad"
+
+block: # issue #22605 for templates, original complex example
+  type Xxx = enum
+    error
+    value
+
+  type
+    Result[T, E] = object
+      when T is void:
+        when E is void:
+          oResultPrivate*: bool
+        else:
+          case oResultPrivate*: bool
+          of false:
+            eResultPrivate*: E
+          of true:
+            discard
+      else:
+        when E is void:
+          case oResultPrivate*: bool
+          of false:
+            discard
+          of true:
+            vResultPrivate*: T
+        else:
+          case oResultPrivate*: bool
+          of false:
+            eResultPrivate*: E
+          of true:
+            vResultPrivate*: T
+
+  template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped =
+    let s = (self) # TODO avoid copy
+    case s.oResultPrivate
+    of true:
+      s.vResultPrivate
+    of false:
+      when E isnot void:
+        template error: untyped {.used, inject.} = s.eResultPrivate
+      def
+
+  proc f(): Result[int, cstring] =
+    Result[int, cstring](oResultPrivate: false, eResultPrivate: "f")
+
+  template g(T: type): string =
+    var res = "ok"
+    let x = f().valueOr:
+      res = $error
+      123
+    res
+
+  doAssert g(int) == "f"
+
+  template g2(T: type): string =
+    bind error # use the bad version on purpose
+    var res = "ok"
+    let x = f().valueOr:
+      res = $error
+      123
+    res
+
+  doAssert g2(int) == "error"
+
+block: # issue #23865 for templates
+  type Xxx = enum
+    error
+    value
+
+  type
+    Result[T, E] = object
+      when T is void:
+        when E is void:
+          oResultPrivate: bool
+        else:
+          case oResultPrivate: bool
+          of false:
+            eResultPrivate: E
+          of true:
+            discard
+      else:
+        when E is void:
+          case oResultPrivate: bool
+          of false:
+            discard
+          of true:
+            vResultPrivate: T
+        else:
+          case oResultPrivate: bool
+          of false:
+            eResultPrivate: E
+          of true:
+            vResultPrivate: T
+
+  func error[T, E](self: Result[T, E]): E =
+    ## Fetch error of result if set, or raise Defect
+    case self.oResultPrivate
+    of true:
+      when T isnot void:
+        raiseResultDefect("Trying to access error when value is set", self.vResultPrivate)
+      else:
+        raiseResultDefect("Trying to access error when value is set")
+    of false:
+      when E isnot void:
+        self.eResultPrivate
+
+  template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped =
+    let s = (self) # TODO avoid copy
+    case s.oResultPrivate
+    of true:
+      s.vResultPrivate
+    of false:
+      when E isnot void:
+        template error: untyped {.used, inject.} = s.eResultPrivate
+      def
+  proc f(): Result[int, cstring] =
+    Result[int, cstring](oResultPrivate: false, eResultPrivate: "f")
+  template g(T: type): string =
+    var res = "ok"
+    let x = f().valueOr:
+      res = $error
+      123
+    res
+  doAssert g(int) == "f"
+
+import std/sequtils
+
+block: # issue #15314
+  var it: string
+  var nums = @[1,2,3]
+
+  template doubleNums() =
+    nums.applyIt(it * 2)
+
+  doubleNums()
+  doAssert nums == @[2, 4, 6]
diff --git a/tests/template/topensymoverride.nim b/tests/template/topensymoverride.nim
new file mode 100644
index 000000000..3d4bb59f1
--- /dev/null
+++ b/tests/template/topensymoverride.nim
@@ -0,0 +1,39 @@
+discard """
+  matrix: "--skipParentCfg --filenames:legacyRelProj"
+"""
+
+const value = "captured"
+template fooOld(x: int, body: untyped): untyped =
+  let value {.inject.} = "injected"
+  body
+template foo(x: int, body: untyped): untyped =
+  let value {.inject.} = "injected"
+  {.push experimental: "genericsOpenSym".}
+  body
+  {.pop.}
+
+proc old[T](): string =
+  fooOld(123):
+    return value
+doAssert old[int]() == "captured"
+
+template oldTempl(): string =
+  block:
+    var res: string
+    fooOld(123):
+      res = value
+    res
+doAssert oldTempl() == "captured"
+
+proc bar[T](): string =
+  foo(123):
+    return value
+doAssert bar[int]() == "injected"
+
+template barTempl(): string =
+  block:
+    var res: string
+    foo(123):
+      res = value
+    res
+doAssert barTempl() == "injected"
diff --git a/tests/template/topensymwarning.nim b/tests/template/topensymwarning.nim
new file mode 100644
index 000000000..0bbe0a9fb
--- /dev/null
+++ b/tests/template/topensymwarning.nim
@@ -0,0 +1,60 @@
+discard """
+  matrix: "--skipParentCfg --filenames:legacyRelProj"
+"""
+
+type Xxx = enum
+  error
+  value
+
+type
+  Result[T, E] = object
+    when T is void:
+      when E is void:
+        oResultPrivate*: bool
+      else:
+        case oResultPrivate*: bool
+        of false:
+          eResultPrivate*: E
+        of true:
+          discard
+    else:
+      when E is void:
+        case oResultPrivate*: bool
+        of false:
+          discard
+        of true:
+          vResultPrivate*: T
+      else:
+        case oResultPrivate*: bool
+        of false:
+          eResultPrivate*: E
+        of true:
+          vResultPrivate*: T
+
+template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped =
+  let s = (self) # TODO avoid copy
+  case s.oResultPrivate
+  of true:
+    s.vResultPrivate
+  of false:
+    when E isnot void:
+      template error: untyped {.used, inject.} = s.eResultPrivate
+    def
+
+proc f(): Result[int, cstring] =
+  Result[int, cstring](oResultPrivate: false, eResultPrivate: "f")
+
+template g(T: type): string =
+  var res = "ok"
+  let x = f().valueOr:
+    {.push warningAsError[IgnoredSymbolInjection]: on.}
+    # test spurious error
+    discard true
+    let _ = f
+    {.pop.}
+    res = $error #[tt.Warning
+           ^ a new symbol 'error' has been injected during template or generic instantiation, however 'error' [enumField declared in topensymwarning.nim(6, 3)] captured at the proc declaration will be used instead; either enable --experimental:openSym to use the injected symbol, or `bind` this captured symbol explicitly [IgnoredSymbolInjection]]#
+    123
+  res
+
+discard g(int)
diff --git a/tests/template/tqualifiedtype.nim b/tests/template/tqualifiedtype.nim
new file mode 100644
index 000000000..6497af6ee
--- /dev/null
+++ b/tests/template/tqualifiedtype.nim
@@ -0,0 +1,25 @@
+# issue #19866
+
+# Switch module import order to switch which of last two
+# doAsserts fails
+import mqualifiedtype1
+import mqualifiedtype2
+
+# this isn't officially supported but needed to point out the issue:
+template f(moduleName: untyped): int = sizeof(`moduleName`.A)
+template g(someType:   untyped): int = sizeof(someType)
+
+# These are legitimately true.
+doAssert sizeof(mqualifiedtype1.A) != sizeof(mqualifiedtype2.A)
+doAssert g(mqualifiedtype1.A) != g(mqualifiedtype2.A)
+
+# Which means that this should not be true, but is in Nim 1.6
+doAssert f(`mqualifiedtype1`) != f(`mqualifiedtype2`)
+doAssert f(mqualifiedtype1) != f(mqualifiedtype2)
+
+# These should be true, but depending on import order, exactly one
+# fails in Nim 1.2, 1.6 and devel.
+doAssert f(`mqualifiedtype1`) == g(mqualifiedtype1.A)
+doAssert f(`mqualifiedtype2`) == g(mqualifiedtype2.A)
+doAssert f(mqualifiedtype1) == g(mqualifiedtype1.A)
+doAssert f(mqualifiedtype2) == g(mqualifiedtype2.A)
diff --git a/tests/threads/tmembug.nim b/tests/threads/tmembug.nim
new file mode 100644
index 000000000..3618f0ecc
--- /dev/null
+++ b/tests/threads/tmembug.nim
@@ -0,0 +1,51 @@
+
+import std / [atomics, strutils, sequtils]
+
+type
+  BackendMessage* = object
+    field*: seq[int]
+
+var
+  chan1: Channel[BackendMessage]
+  chan2: Channel[BackendMessage]
+
+chan1.open()
+chan2.open()
+
+proc routeMessage*(msg: BackendMessage) =
+  discard chan2.trySend(msg)
+
+var
+  recv: Thread[void]
+  stopToken: Atomic[bool]
+
+proc recvMsg() =
+  while not stopToken.load(moRelaxed):
+    let resp = chan1.tryRecv()
+    if resp.dataAvailable:
+      routeMessage(resp.msg)
+      echo "child consumes ", formatSize getOccupiedMem()
+
+createThread[void](recv, recvMsg)
+
+const MESSAGE_COUNT = 100
+
+proc main() =
+  let msg: BackendMessage = BackendMessage(field: (0..500).toSeq())
+  for j in 0..0: #100:
+    echo "New iteration"
+
+    for _ in 1..MESSAGE_COUNT:
+      chan1.send(msg)
+    echo "After sending"
+
+    var counter = 0
+    while counter < MESSAGE_COUNT:
+      let resp = recv(chan2)
+      counter.inc
+    echo "After receiving ", formatSize getOccupiedMem()
+
+  stopToken.store true, moRelaxed
+  joinThreads(recv)
+
+main()
diff --git a/tests/tools/tunused_imports.nim b/tests/tools/tunused_imports.nim
index 31d6cf7d7..539608ad6 100644
--- a/tests/tools/tunused_imports.nim
+++ b/tests/tools/tunused_imports.nim
@@ -1,9 +1,12 @@
 discard """
   cmd: '''nim c --hint:Processing:off $file'''
   nimout: '''
-tunused_imports.nim(11, 10) Warning: BEGIN [User]
-tunused_imports.nim(36, 10) Warning: END [User]
-tunused_imports.nim(34, 8) Warning: imported and not used: 'strutils' [UnusedImport]
+tunused_imports.nim(14, 10) Warning: BEGIN [User]
+tunused_imports.nim(41, 10) Warning: END [User]
+tunused_imports.nim(37, 8) Warning: imported and not used: 'strutils' [UnusedImport]
+tunused_imports.nim(38, 13) Warning: imported and not used: 'strtabs' [UnusedImport]
+tunused_imports.nim(38, 22) Warning: imported and not used: 'cstrutils' [UnusedImport]
+tunused_imports.nim(39, 12) Warning: imported and not used: 'macrocache' [UnusedImport]
 '''
   action: "compile"
 """
@@ -32,5 +35,7 @@ macro bar(): untyped =
 bar()
 
 import strutils
+import std/[strtabs, cstrutils]
+import std/macrocache
 
 {.warning: "END".}
diff --git a/tests/trmacros/tor.nim b/tests/trmacros/tor.nim
index 6b4e71216..9defc4d1b 100644
--- a/tests/trmacros/tor.nim
+++ b/tests/trmacros/tor.nim
@@ -1,7 +1,7 @@
 discard """
   output: '''
 3
-0
+30
 true
 '''
 """
@@ -15,7 +15,9 @@ echo z
 
 
 template arithOps: untyped = (`+` | `-` | `*`)
-template testOr{ (arithOps{f})(a, b) }(a, b, f: untyped): untyped = f(a mod 10, b)
+template testOr{ (arithOps{f})(a, b) }(a, b, f: untyped): untyped =
+  {.noRewrite.}:
+    f(a mod 10, b)
 
 let xx = 10
 echo 10*xx
diff --git a/tests/trmacros/trmacros_various2.nim b/tests/trmacros/trmacros_various2.nim
index 257ee8ba6..981df4ca6 100644
--- a/tests/trmacros/trmacros_various2.nim
+++ b/tests/trmacros/trmacros_various2.nim
@@ -70,7 +70,9 @@ block tstar:
     for i in 1..len(s)-1: result.add s[i]
     inc calls
 
-  template optConc{ `&&` * a }(a: string): string = &&a
+  template optConc{ `&&` * a }(a: string): string =
+    {.noRewrite.}:
+      &&a
 
   let space = " "
   echo "my" && (space & "awe" && "some " ) && "concat"
diff --git a/tests/typerel/tuncheckedarray_eq.nim b/tests/typerel/tuncheckedarray_eq.nim
new file mode 100644
index 000000000..c07696b5f
--- /dev/null
+++ b/tests/typerel/tuncheckedarray_eq.nim
@@ -0,0 +1,2 @@
+type p = ptr UncheckedArray[char]
+doAssert p is ptr UncheckedArray
\ No newline at end of file
diff --git a/tests/types/tinheritgenericparameter.nim b/tests/types/tinheritgenericparameter.nim
index c88c50b7b..d0d313635 100644
--- a/tests/types/tinheritgenericparameter.nim
+++ b/tests/types/tinheritgenericparameter.nim
@@ -4,11 +4,11 @@ discard """
   nimout:'''
 tinheritgenericparameter.nim(36, 15) Error: Cannot inherit from: 'MyObject'
 tinheritgenericparameter.nim(36, 15) Error: Cannot inherit from: 'MyObject'
-tinheritgenericparameter.nim(36, 23) Error: object constructor needs an object type [proxy]
+tinheritgenericparameter.nim(36, 23) Error: object constructor needs an object type [error]
 tinheritgenericparameter.nim(36, 23) Error: expression '' has no type (or is ambiguous)
 tinheritgenericparameter.nim(37, 15) Error: Cannot inherit from: 'int'
 tinheritgenericparameter.nim(37, 15) Error: Cannot inherit from: 'int'
-tinheritgenericparameter.nim(37, 23) Error: object constructor needs an object type [proxy]
+tinheritgenericparameter.nim(37, 23) Error: object constructor needs an object type [error]
 tinheritgenericparameter.nim(37, 23) Error: expression '' has no type (or is ambiguous)
 '''
 """
diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim
index 64b3d03c0..c95b63c90 100644
--- a/tests/types/tisopr.nim
+++ b/tests/types/tisopr.nim
@@ -165,3 +165,7 @@ block: # previously tisop.nim
       doAssert f.y.typeof is float
       doAssert f.z.typeof is float
   p(A, f)
+
+block: # issue #22850
+  doAssert not (type is int)
+  doAssert not (typedesc is int)
diff --git a/tests/types/ttopdowninference.nim b/tests/types/ttopdowninference.nim
index 2a26e0e34..765761e99 100644
--- a/tests/types/ttopdowninference.nim
+++ b/tests/types/ttopdowninference.nim
@@ -325,3 +325,9 @@ block: # bug #22180
         else:
           (ref A)(nil)
   doAssert y.isNil
+
+block: # issue #24164, related regression
+  proc foo(x: proc ()) = discard
+  template bar(x: untyped = nil) =
+    foo(x)
+  bar()
diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim
index b27c327a9..c9aeb94d8 100644
--- a/tests/varres/tprevent_forloopvar_mutations.nim
+++ b/tests/varres/tprevent_forloopvar_mutations.nim
@@ -2,7 +2,7 @@ discard """
   errormsg: "type mismatch: got <int>"
   nimout: '''tprevent_forloopvar_mutations.nim(16, 3) Error: type mismatch: got <int>
 but expected one of:
-proc inc[T: Ordinal](x: var T; y: int = 1)
+proc inc[T, V: Ordinal](x: var T; y: V = 1)
   first type mismatch at position: 1
   required type for x: var T: Ordinal
   but expression 'i' is immutable, not 'var'
diff --git a/tests/views/tviews1.nim b/tests/views/tviews1.nim
index 1cc9fcdec..9785d25e5 100644
--- a/tests/views/tviews1.nim
+++ b/tests/views/tviews1.nim
@@ -124,3 +124,13 @@ proc bug22597 = # bug #22597
   doAssert i == 1
 
 bug22597()
+
+block: # bug #20048
+  type
+    Test = object
+      tokens: openArray[string]
+
+  func init(Self: typedesc[Test], tokens: openArray[string]): Self = Self(tokens: tokens)
+
+  let data = Test.init(["123"])
+  doAssert @(data.tokens) == @["123"] 
diff --git a/tests/views/tviews2.nim b/tests/views/tviews2.nim
new file mode 100644
index 000000000..29aff76df
--- /dev/null
+++ b/tests/views/tviews2.nim
@@ -0,0 +1,90 @@
+discard """
+  targets: "c js"
+"""
+
+{.experimental: "views".}
+
+block:
+  type
+    Foo = object
+      id: openArray[char]
+
+  proc foo(): Foo =
+    var source = "1245"
+    result = Foo(id: source.toOpenArray(0, 1))
+
+  doAssert foo().id == @['1', '2']
+
+block: # bug #15778
+  type
+    Reader = object
+      data: openArray[char]
+      current: int
+
+  var count = 0
+
+  proc read(data: var Reader, length: int): openArray[char] =
+    inc count
+    let start = data.current
+    data.current.inc length
+    return data.data.toOpenArray(start, data.current-1)
+
+  var data = "hello there"
+  var reader = Reader(data: data.toOpenArray(0, data.len-1), current: 0)
+  doAssert @(reader.read(2)) == @['h', 'e']
+  doAssert @(reader.read(3)) == @['l', 'l', 'o']
+  doAssert count == 2
+
+block: # bug #16671
+  block:
+    type X = ref object of RootObj
+    type Y = ref object of X
+      field: openArray[int]
+
+    var s: seq[X]
+    proc f() =
+      s.add(Y(field: [1]))
+
+    f()
+
+  block:
+    type X = ref object of RootObj
+    type Y = ref object of X
+      field: openArray[int]
+
+    var s: seq[X]
+    proc f() =
+      s.add(Y(field: toOpenArray([1, 2, 3], 0, 1)))
+
+    f()
+
+block: # bug #15746
+  type
+    Reader = object
+      data: openArray[char]
+      current: int
+
+  proc initReader(data: openArray[char], offset = 0): Reader =
+    result = Reader(data: data, current: offset)
+
+  let s = "\x01\x00\x00\x00"
+  doAssert initReader(s).data[0].int == 1
+
+block:
+  proc foo(x: openArray[char]) =
+    discard x
+
+  foo("12254")
+  foo(@['a', 'b'])
+
+  var a1 = "12254"
+  foo(a1)
+
+  var a2 = @['a', 'b']
+  foo(a2)
+
+  var s = "138443"
+  var ooo: openArray[char] = s
+  var xxx: openArray[char] = ooo
+  foo(ooo)
+  foo(xxx)
diff --git a/tests/vm/tconstarrayresem.nim b/tests/vm/tconstarrayresem.nim
new file mode 100644
index 000000000..6701cfe4d
--- /dev/null
+++ b/tests/vm/tconstarrayresem.nim
@@ -0,0 +1,29 @@
+# issue #23010
+
+type
+  Result[T, E] = object
+    case oResult: bool
+    of false:
+      discard
+    of true:
+      vResult: T
+
+  Opt[T] = Result[T, void]
+
+template ok[T, E](R: type Result[T, E], x: untyped): R =
+  R(oResult: true, vResult: x)
+
+template c[T](v: T): Opt[T] = Opt[T].ok(v)
+
+type
+  FixedBytes[N: static[int]] = distinct array[N, byte]
+
+  H = object
+    d: FixedBytes[2]
+
+const b = default(H)
+template g(): untyped =
+  const t = default(H)
+  b
+
+discard c(g())
diff --git a/tests/vm/tconstscope1.nim b/tests/vm/tconstscope1.nim
new file mode 100644
index 000000000..41c45a28f
--- /dev/null
+++ b/tests/vm/tconstscope1.nim
@@ -0,0 +1,5 @@
+# issue #5395
+
+const a = (var b = 3; b)
+echo b #[tt.Error
+     ^ undeclared identifier: 'b']#
diff --git a/tests/vm/tconstscope2.nim b/tests/vm/tconstscope2.nim
new file mode 100644
index 000000000..d858e96c2
--- /dev/null
+++ b/tests/vm/tconstscope2.nim
@@ -0,0 +1,5 @@
+const
+  a = (var x = 3; x)
+  # should we allow this?
+  b = x #[tt.Error
+      ^ undeclared identifier: 'x']#
diff --git a/tests/vm/tconsttable.nim b/tests/vm/tconsttable.nim
index 64a74a59d..152a33cba 100644
--- a/tests/vm/tconsttable.nim
+++ b/tests/vm/tconsttable.nim
@@ -17,3 +17,18 @@ x = "ah"
 echo foo[x]
 x = "possible."
 echo foo[x]
+
+block: # bug #19840
+  const testBytes = [byte 0xD8, 0x08, 0xDF, 0x45, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x61]
+  var tempStr = "__________________"
+
+  tempStr.prepareMutation
+  copyMem(addr tempStr[0], addr testBytes[0], testBytes.len)
+
+block: # bug #22389
+  func foo(): ptr UncheckedArray[byte] =
+    const bar = [77.byte]
+    cast[ptr UncheckedArray[byte]](addr bar[0])
+
+  doAssert foo()[0] == 77
+
diff --git a/tests/vm/tconvaddr.nim b/tests/vm/tconvaddr.nim
new file mode 100644
index 000000000..9762a9e59
--- /dev/null
+++ b/tests/vm/tconvaddr.nim
@@ -0,0 +1,49 @@
+block: # issue #24097
+  type Foo = distinct int
+  proc foo(x: var Foo) =
+    int(x) += 1
+  proc bar(x: var int) =
+    x += 1
+  static:
+    var x = Foo(1)
+    int(x) = int(x) + 1
+    doAssert x.int == 2
+    int(x) += 1
+    doAssert x.int == 3
+    foo(x)
+    doAssert x.int == 4
+    bar(int(x)) # need vmgen flags propagated for this
+    doAssert x.int == 5
+  type Bar = object
+    x: Foo
+  static:
+    var obj = Bar(x: Foo(1))
+    int(obj.x) = int(obj.x) + 1
+    doAssert obj.x.int == 2
+    int(obj.x) += 1
+    doAssert obj.x.int == 3
+    foo(obj.x)
+    doAssert obj.x.int == 4
+    bar(int(obj.x)) # need vmgen flags propagated for this
+    doAssert obj.x.int == 5
+  static:
+    var arr = @[Foo(1)]
+    int(arr[0]) = int(arr[0]) + 1
+    doAssert arr[0].int == 2
+    int(arr[0]) += 1
+    doAssert arr[0].int == 3
+    foo(arr[0])
+    doAssert arr[0].int == 4
+    bar(int(arr[0])) # need vmgen flags propagated for this
+    doAssert arr[0].int == 5
+  proc testResult(): Foo =
+    result = Foo(1)
+    int(result) = int(result) + 1
+    doAssert result.int == 2
+    int(result) += 1
+    doAssert result.int == 3
+    foo(result)
+    doAssert result.int == 4
+    bar(int(result)) # need vmgen flags propagated for this
+    doAssert result.int == 5
+  doAssert testResult().int == 5
diff --git a/tests/vm/tgenericcompiletimeproc.nim b/tests/vm/tgenericcompiletimeproc.nim
new file mode 100644
index 000000000..08099ebbe
--- /dev/null
+++ b/tests/vm/tgenericcompiletimeproc.nim
@@ -0,0 +1,36 @@
+block: # issue #10753
+  proc foo(x: int): int {.compileTime.} = x
+  const a = foo(123)
+  doAssert foo(123) == a
+
+  proc bar[T](x: T): T {.compileTime.} = x
+  const b = bar(123)
+  doAssert bar(123) == b
+  const c = bar("abc")
+  doAssert bar("abc") == c
+
+block: # issue #22021
+  proc foo(x: static int): int {.compileTime.} = x + 1
+  doAssert foo(123) == 124
+
+block: # issue #19365
+  proc f[T](x: static T): T {.compileTime.} = x + x
+  doAssert f(123) == 246
+  doAssert f(1.0) == 2.0
+
+block:
+  # don't fold compile time procs in typeof
+  proc fail[T](x: T): T {.compileTime.} =
+    doAssert false
+    x
+  doAssert typeof(fail(123)) is typeof(123)
+  proc p(x: int): int = x
+
+  type Foo = typeof(p(fail(123)))
+
+block: # issue #24150, related regression
+  proc w(T: type): T {.compileTime.} = default(ptr T)[]
+  template y(v: auto): auto = typeof(v) is int
+  discard compiles(y(w int))
+  proc s(): int {.compileTime.} = discard
+  discard s()
diff --git a/tests/vm/tnilclosurecall.nim b/tests/vm/tnilclosurecall.nim
new file mode 100644
index 000000000..449865b9c
--- /dev/null
+++ b/tests/vm/tnilclosurecall.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "attempt to call nil closure"
+  line: 8
+"""
+
+static:
+  let x: proc () = nil
+  x()
diff --git a/tests/vm/tnilclosurecallstacktrace.nim b/tests/vm/tnilclosurecallstacktrace.nim
new file mode 100644
index 000000000..879060e8e
--- /dev/null
+++ b/tests/vm/tnilclosurecallstacktrace.nim
@@ -0,0 +1,23 @@
+discard """
+  action: reject
+  nimout: '''
+stack trace: (most recent call last)
+tnilclosurecallstacktrace.nim(23, 6) tnilclosurecallstacktrace
+tnilclosurecallstacktrace.nim(20, 6) baz
+tnilclosurecallstacktrace.nim(17, 6) bar
+tnilclosurecallstacktrace.nim(14, 4) foo
+tnilclosurecallstacktrace.nim(14, 4) Error: attempt to call nil closure
+'''
+"""
+
+proc foo(x: proc ()) =
+  x()
+
+proc bar(x: proc ()) =
+  foo(x)
+
+proc baz(x: proc ()) =
+  bar(x)
+
+static:
+  baz(nil)
diff --git a/tests/vm/topenarrays.nim b/tests/vm/topenarrays.nim
index 0a822f583..375d2523d 100644
--- a/tests/vm/topenarrays.nim
+++ b/tests/vm/topenarrays.nim
@@ -67,3 +67,23 @@ template fn=
   doAssert test([0,1,2,3,4,5]).id == 0
 fn() # ok
 static: fn()
+
+
+block: # bug #22095
+  type
+    StUint = object
+      limbs: array[4, uint64]
+
+  func shlAddMod(a: var openArray[uint64]) =  
+    a[0] = 10
+
+  func divRem(r: var openArray[uint64]) =
+    shlAddMod(r.toOpenArray(0, 3))
+
+  func fn(): StUint =
+    divRem(result.limbs)
+
+  const
+    z = fn()
+
+  doAssert z.limbs[0] == 10
diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim
index d28f76574..6aeac5529 100644
--- a/tests/vm/tvmmisc.nim
+++ b/tests/vm/tvmmisc.nim
@@ -355,7 +355,7 @@ block: # bug #8007
 block: # bug #14340
   block:
     proc opl3EnvelopeCalcSin0() = discard
-    type EnvelopeSinfunc = proc()
+    type EnvelopeSinfunc = proc() {.nimcall.} # todo: fixme 
     # const EnvelopeCalcSin0 = opl3EnvelopeCalcSin0 # ok
     const EnvelopeCalcSin0: EnvelopeSinfunc = opl3EnvelopeCalcSin0 # was bug
     const envelopeSin = [EnvelopeCalcSin0]
@@ -566,7 +566,7 @@ block:
 block:
   static:
     let x = int 1
-    doAssert $(x.type) == "Foo"  # Foo
+    doAssert $(x.type) == "int"  # Foo
 
 block:
   static:
@@ -766,3 +766,31 @@ block: # issue #15730
 static: # more nil cstring issues
   let x = cstring(nil)
   doAssert x.len == 0
+
+block: # bug #23925
+  type Foo = enum A = -1
+  proc foo =
+    doAssert cast[Foo](-1) == A
+    doAssert ord(A) == -1
+
+  static: foo()
+  foo()
+
+  type E = enum
+    e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 e10 e11 e12 e13 e14 e15 e16 e17 e18 e19 e20
+    e21 e22 e23 e24 e25 e26 e27 e28 e29 e30 e31 e32 e33 e34 e35 e36 e37 e38
+    e39 e40 e41 e42 e43 e44 e45 e46 e47 e48 e49 e50 e51 e52 e53 e54 e55 e56
+    e57 e58 e59 e60 e61 e62 e63 e64 e65 e66 e67 e68 e69 e70 e71 e72 e73 e74
+    e75 e76 e77 e78 e79 e80 e81 e82 e83 e84 e85 e86 e87 e88 e89 e90 e91 e92
+    e93 e94 e95 e96 e97 e98 e99 e100 e101 e102 e103 e104 e105 e106 e107 e108
+    e109 e110 e111 e112 e113 e114 e115 e116 e117 e118 e119 e120 e121 e122
+    e123 e124 e125 e126 e127 e128
+  proc bar =
+    doAssert cast[E](int(e128)) == e128
+
+  static: bar()
+  bar()
+
+static: # bug #21353
+  var s: proc () = default(proc ())
+  doAssert s == nil
diff --git a/tests/vm/tvmopsDanger.nim b/tests/vm/tvmopsDanger.nim
index 5e7bac29a..966feffe6 100644
--- a/tests/vm/tvmopsDanger.nim
+++ b/tests/vm/tvmopsDanger.nim
@@ -3,8 +3,11 @@ discard """
 """
 when defined(nimPreviewSlimSystem):
   import std/assertions
-import std/times
+import std/[times, os]
 
 const foo = getTime()
 let bar = foo
-doAssert bar > low(Time)
\ No newline at end of file
+doAssert bar > low(Time)
+
+static: # bug #23932
+  doAssert getCurrentDir().len > 0
diff --git a/tools/debug/nim-gdb.py b/tools/debug/nim-gdb.py
index 1050197c9..8c9854bda 100644
--- a/tools/debug/nim-gdb.py
+++ b/tools/debug/nim-gdb.py
@@ -151,7 +151,7 @@ class DollarPrintFunction (gdb.Function):
   "Nim's equivalent of $ operator as a gdb function, available in expressions `print $dollar(myvalue)"
 
   dollar_functions = re.findall(
-    '(?:NimStringDesc \*|NimStringV2)\s?(dollar__[A-z0-9_]+?)\(([^,)]*)\);',
+    r'(?:NimStringDesc \*|NimStringV2)\s?(dollar__[A-z0-9_]+?)\(([^,)]*)\);',
     gdb.execute("info functions dollar__", True, True)
   )
 
@@ -168,11 +168,11 @@ class DollarPrintFunction (gdb.Function):
       # this way of overload resolution cannot deal with type aliases,
       # therefore it won't find all overloads.
       if arg_typ == argTypeName:
-        func_value = gdb.lookup_global_symbol(func, gdb.SYMBOL_FUNCTIONS_DOMAIN).value()
+        func_value = gdb.lookup_global_symbol(func, gdb.SYMBOL_FUNCTION_DOMAIN).value()
         return func_value(arg)
 
       elif arg_typ == argTypeName + " *":
-        func_value = gdb.lookup_global_symbol(func, gdb.SYMBOL_FUNCTIONS_DOMAIN).value()
+        func_value = gdb.lookup_global_symbol(func, gdb.SYMBOL_FUNCTION_DOMAIN).value()
         return func_value(arg.address)
 
     if not ignore_errors:
@@ -387,7 +387,7 @@ def enumNti(typeNimName, idString):
 
 class NimEnumPrinter:
   pattern = re.compile(r'^tyEnum_([A-Za-z0-9]+)__([A-Za-z0-9]*)$')
-  enumReprProc = gdb.lookup_global_symbol("reprEnum", gdb.SYMBOL_FUNCTIONS_DOMAIN)
+  enumReprProc = gdb.lookup_global_symbol("reprEnum", gdb.SYMBOL_FUNCTION_DOMAIN)
 
   def __init__(self, val):
     self.val = val
@@ -677,7 +677,7 @@ def makematcher(klass):
   return matcher
 
 def register_nim_pretty_printers_for_object(objfile):
-  nimMainSym = gdb.lookup_global_symbol("NimMain", gdb.SYMBOL_FUNCTIONS_DOMAIN)
+  nimMainSym = gdb.lookup_global_symbol("NimMain", gdb.SYMBOL_FUNCTION_DOMAIN)
   if nimMainSym and nimMainSym.symtab.objfile == objfile:
     print("set Nim pretty printers for ", objfile.filename)
 
diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim
index 0753248bc..946945346 100644
--- a/tools/dochack/dochack.nim
+++ b/tools/dochack/dochack.nim
@@ -328,8 +328,8 @@ proc copyToClipboard*() {.exportc.} =
 
     function updatePreTags() {
 
-      const allPreTags = document.querySelectorAll("pre")
-    
+      const allPreTags = document.querySelectorAll("pre:not(.line-nums)")
+
       allPreTags.forEach((e) => {
       
           const div = document.createElement("div")
diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim
index bd5c4ecbe..477fb29fa 100644
--- a/tools/kochdocs.nim
+++ b/tools/kochdocs.nim
@@ -325,7 +325,8 @@ proc nim2pdf(src: string, dst: string, nimArgs: string) =
       exec(cmd)
   moveFile(texFile.changeFileExt("pdf"), dst)
 
-proc buildPdfDoc*(nimArgs, destPath: string) =
+proc buildPdfDoc*(args: string, destPath: string) =
+  let args = nimArgs & " " & args
   var pdfList: seq[string]
   createDir(destPath)
   if os.execShellCmd("xelatex -version") != 0:
@@ -334,7 +335,7 @@ proc buildPdfDoc*(nimArgs, destPath: string) =
     for src in items(mdPdfList):
       let dst = destPath / src.lastPathPart.changeFileExt("pdf")
       pdfList.add dst
-      nim2pdf(src, dst, nimArgs)
+      nim2pdf(src, dst, args)
   echo "\nOutput PDF files: \n  ", pdfList.join(" ") # because `nim2pdf` is a bit verbose
 
 proc buildJS(): string =
diff --git a/tools/niminst/buildsh.nimf b/tools/niminst/buildsh.nimf
index 6b99c49ee..063a02779 100644
--- a/tools/niminst/buildsh.nimf
+++ b/tools/niminst/buildsh.nimf
@@ -122,6 +122,7 @@ case $uos in
   *netbsd* )
     myos="netbsd"
     LINK_FLAGS="$LINK_FLAGS -lm"
+    ucpu=`uname -p`
     ;;
   *darwin* )
     myos="macosx"
diff --git a/tools/niminst/makefile.nimf b/tools/niminst/makefile.nimf
index b392ab472..002bc0592 100644
--- a/tools/niminst/makefile.nimf
+++ b/tools/niminst/makefile.nimf
@@ -45,6 +45,7 @@ endif
 ifeq ($(uos),netbsd)
   myos = netbsd
   LDFLAGS += -lm
+  ucpu = $(shell sh -c 'uname -p')
 endif
 ifeq ($(uos),darwin)
   myos = macosx
diff --git a/tools/unicode_parsedata.nim b/tools/unicode_parsedata.nim
index cca377f51..bd12998d1 100644
--- a/tools/unicode_parsedata.nim
+++ b/tools/unicode_parsedata.nim
@@ -26,34 +26,54 @@ var
 
 
 proc parseData(data: seq[string]) =
-  for line in data:
-    let
-      fields = line.split(';')
-      code = fields[0].parseHexInt()
-      category = fields[2]
-      uc = fields[12]
-      lc = fields[13]
-      tc = fields[14]
-
+  proc doAdd(firstCode, lastCode: int, category, uc, lc, tc: string) =
     if category notin spaces and category notin letters:
-      continue
+      return
 
+    if firstCode != lastCode:
+      doAssert uc == "" and lc == "" and tc == ""
     if uc.len > 0:
-      let diff = 500 + uc.parseHexInt() - code
-      toUpper.add (code, diff)
+      let diff = 500 + uc.parseHexInt() - firstCode
+      toUpper.add (firstCode, diff)
     if lc.len > 0:
-      let diff = 500 + lc.parseHexInt() - code
-      toLower.add (code, diff)
+      let diff = 500 + lc.parseHexInt() - firstCode
+      toLower.add (firstCode, diff)
     if tc.len > 0 and tc != uc:
       # if titlecase is different than uppercase
-      let diff = 500 + tc.parseHexInt() - code
+      let diff = 500 + tc.parseHexInt() - firstCode
       if diff != 500:
-        toTitle.add (code, diff)
+        toTitle.add (firstCode, diff)
 
-    if category in spaces:
-      unispaces.add code
+    for code in firstCode..lastCode:
+      if category in spaces:
+        unispaces.add code
+      else:
+        alphas.add code
+
+  var idx = 0
+  while idx < data.len:
+    let
+      line = data[idx]
+      fields = line.split(';')
+      code = fields[0].parseHexInt()
+      name = fields[1]
+      category = fields[2]
+      uc = fields[12]
+      lc = fields[13]
+      tc = fields[14]
+    inc(idx)
+    if name.endsWith(", First>"):
+      doAssert idx < data.len
+      let
+        nextLine = data[idx]
+        nextFields = nextLine.split(';')
+        nextCode = nextFields[0].parseHexInt()
+        nextName = nextFields[1]
+      inc(idx)
+      doAssert nextName.endsWith(", Last>")
+      doAdd(code, nextCode, category, uc, lc, tc)
     else:
-      alphas.add code
+      doAdd(code, code, category, uc, lc, tc)
 
 proc splitRanges(a: seq[Singlets], r: var seq[Ranges], s: var seq[Singlets]) =
   ## Splits `toLower`, `toUpper` and `toTitle` into separate sequences:
@@ -153,18 +173,18 @@ proc createHeader(output: var string) =
 
 proc `$`(r: Ranges): string =
   let
-    start = "0x" & toHex(r.start, 5)
-    stop = "0x" & toHex(r.stop, 5)
+    start = "0x" & toHex(r.start, 5) & "'i32"
+    stop = "0x" & toHex(r.stop, 5) & "'i32"
   result = "$#, $#, $#,\n" % [start, stop, $r.diff]
 
 proc `$`(r: Singlets): string =
-  let code = "0x" & toHex(r.code, 5)
+  let code = "0x" & toHex(r.code, 5) & "'i32"
   result = "$#, $#,\n" % [code, $r.diff]
 
 proc `$`(r: NonLetterRanges): string =
   let
-    start = "0x" & toHex(r.start, 5)
-    stop = "0x" & toHex(r.stop, 5)
+    start = "0x" & toHex(r.start, 5) & "'i32"
+    stop = "0x" & toHex(r.stop, 5) & "'i32"
   result = "$#, $#,\n" % [start, stop]
 
 
@@ -178,7 +198,7 @@ proc outputSeq(s: seq[Ranges|Singlets|NonLetterRanges], name: string,
 proc outputSeq(s: seq[int], name: string, output: var string) =
   output.add "  $# = [\n" % name
   for i in s:
-    output.add "    0x$#,\n" % toHex(i, 5)
+    output.add "    0x$#'i32,\n" % toHex(i, 5)
   output.add "  ]\n\n"
 
 proc outputSpaces(s: seq[int], name: string, output: var string) =